Update Theia, CLI and LS (#610)

* Update Theia to 1.19.0

* update CLI to 0.20.0-rc3

* Add language selector to settings

* updated language server and vscode-arduino-tools

* update Language Server flags

* get cli port from config

* force native menu on windows

* pinned Language Server to rc2

* fix search icon

* update CLI version
This commit is contained in:
Francesco Stasi
2021-11-29 15:54:13 +01:00
committed by GitHub
parent 6e34a27b7e
commit dd76f9180c
97 changed files with 1437 additions and 1310 deletions

View File

@@ -1,3 +1,13 @@
import { inject, injectable, postConstruct } from 'inversify';
import * as React from 'react';
import { remote } from 'electron';
import {
BoardsService,
Port,
SketchesService,
ExecutableService,
Sketch,
} from '../common/protocol';
import { Mutex } from 'async-mutex';
import {
MAIN_MENU_BAR,
@@ -13,7 +23,7 @@ import {
StatusBar,
StatusBarAlignment,
} from '@theia/core/lib/browser';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution';
@@ -40,16 +50,10 @@ import { OutputContribution } from '@theia/output/lib/browser/output-contributio
import { ScmContribution } from '@theia/scm/lib/browser/scm-contribution';
import { SearchInWorkspaceFrontendContribution } from '@theia/search-in-workspace/lib/browser/search-in-workspace-frontend-contribution';
import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-contribution';
import { inject, injectable, postConstruct } from 'inversify';
import * as React from 'react';
import { remote } from 'electron';
import {
BoardsService,
Port,
SketchesService,
ExecutableService,
Sketch,
} from '../common/protocol';
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { FileChangeType } from '@theia/filesystem/lib/browser';
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
import { ConfigService } from '../common/protocol/config-service';
import { ArduinoCommands } from './arduino-commands';
import { BoardsConfig } from './boards/boards-config';
@@ -60,13 +64,9 @@ import { EditorMode } from './editor-mode';
import { ArduinoMenus } from './menu/arduino-menus';
import { MonitorViewContribution } from './serial/monitor/monitor-view-contribution';
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 { 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';
import { SketchbookWidgetContribution } from './widgets/sketchbook/sketchbook-widget-contribution';
const INIT_AVR_PACKAGES = 'initializedAvrPackages';
@@ -340,15 +340,14 @@ export class ArduinoFrontendContribution
);
}
}
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
const [clangdPath, cliPath, lsPath, cliConfigPath] = await Promise.all([
const { clangdUri, lsUri } = await this.executableService.list();
const [clangdPath, lsPath] = await Promise.all([
this.fileService.fsPath(new URI(clangdUri)),
this.fileService.fsPath(new URI(cliUri)),
this.fileService.fsPath(new URI(lsUri)),
this.fileService.fsPath(
new URI(await this.configService.getCliConfigFileUri())
),
]);
const config = await this.configService.getConfiguration();
this.languageServerFqbn = await Promise.race([
new Promise<undefined>((_, reject) =>
setTimeout(
@@ -360,10 +359,10 @@ export class ArduinoFrontendContribution
'arduino.languageserver.start',
{
lsPath,
cliPath,
cliDaemonAddr: `localhost:${config.daemon.port}`,
clangdPath,
log: currentSketchPath ? currentSketchPath : log,
cliConfigPath,
cliDaemonInstance: '1',
board: {
fqbn,
name: name ? `"${name}"` : undefined,

View File

@@ -154,7 +154,7 @@ import {
} from '../common/protocol/examples-service';
import { BuiltInExamples, LibraryExamples } from './contributions/examples';
import { IncludeLibrary } from './contributions/include-library';
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/browser/output-channel';
import { OutputChannelManager } from './theia/output/output-channel';
import {
OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl,
@@ -190,12 +190,12 @@ import { BoardSelection } from './contributions/board-selection';
import { OpenRecentSketch } from './contributions/open-recent-sketch';
import { Help } from './contributions/help';
import { bindArduinoPreferences } from './arduino-preferences';
import { SettingsService } from './dialogs/settings/settings';
import {
SettingsService,
SettingsDialog,
SettingsWidget,
SettingsDialogProps,
} from './settings';
} from './dialogs/settings/settings-dialog';
import { AddFile } from './contributions/add-file';
import { ArchiveSketch } from './contributions/archive-sketch';
import { OutputToolbarContribution as TheiaOutputToolbarContribution } from '@theia/output/lib/browser/output-toolbar-contribution';
@@ -207,6 +207,8 @@ import { DebugConfigurationManager } from './theia/debug/debug-configuration-man
import { DebugConfigurationManager as TheiaDebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager';
import { SearchInWorkspaceWidget as TheiaSearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget';
import { SearchInWorkspaceWidget } from './theia/search-in-workspace/search-in-workspace-widget';
import { SearchInWorkspaceFactory as TheiaSearchInWorkspaceFactory } from '@theia/search-in-workspace/lib/browser/search-in-workspace-factory';
import { SearchInWorkspaceFactory } from './theia/search-in-workspace/search-in-workspace-factory';
import { SearchInWorkspaceResultTreeWidget as TheiaSearchInWorkspaceResultTreeWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-result-tree-widget';
import { SearchInWorkspaceResultTreeWidget } from './theia/search-in-workspace/search-in-workspace-result-tree-widget';
import { MonacoEditorProvider } from './theia/monaco/monaco-editor-provider';
@@ -259,7 +261,7 @@ import {
UserFieldsDialogProps,
UserFieldsDialogWidget,
} from './dialogs/user-fields/user-fields-dialog';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
const ElementQueries = require('css-element-queries/src/ElementQueries');
@@ -492,6 +494,12 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(SearchInWorkspaceWidget).toSelf();
rebind(TheiaSearchInWorkspaceWidget).toService(SearchInWorkspaceWidget);
// replace search icon
rebind(TheiaSearchInWorkspaceFactory)
.to(SearchInWorkspaceFactory)
.inSingletonScope();
rebind(TheiaSearchInWorkspaceResultTreeWidget).toDynamicValue(
({ container }) => {
const childContainer = createTreeContainer(container);
@@ -678,7 +686,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(SettingsWidget).toSelf().inSingletonScope();
bind(SettingsDialog).toSelf().inSingletonScope();
bind(SettingsDialogProps).toConstantValue({
title: 'Preferences',
title: nls.localize(
'vscode/preferences.contribution/preferences',
'Preferences'
),
});
bind(StorageWrapper).toSelf().inSingletonScope();

View File

@@ -6,7 +6,7 @@ import {
PreferenceContribution,
PreferenceSchema,
} from '@theia/core/lib/browser/preferences';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import { CompilerWarningLiterals, CompilerWarnings } from '../common/protocol';
export const ArduinoConfigSchema: PreferenceSchema = {

View File

@@ -10,7 +10,7 @@ import { BoardsServiceProvider } from './boards-service-provider';
import { BoardsConfig } from './boards-config';
import { Installable, ResponseServiceArduino } from '../../common/protocol';
import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
/**
* Listens on `BoardsConfig.Config` changes, if a board is selected which does not

View File

@@ -6,7 +6,7 @@ import { BoardsConfig } from './boards-config';
import { BoardsService } from '../../common/protocol/boards-service';
import { BoardsServiceProvider } from './boards-service-provider';
import { BoardsConfigDialogWidget } from './boards-config-dialog-widget';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BoardsConfigDialogProps extends DialogProps {}

View File

@@ -14,8 +14,8 @@ import {
AvailableBoard,
BoardsServiceProvider,
} from './boards-service-provider';
import { nls } from '@theia/core/lib/browser/nls';
import { naturalCompare } from '../../common/utils';
import { nls } from '@theia/core/lib/common';
export namespace BoardsConfig {
export interface Config {

View File

@@ -12,7 +12,7 @@ import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { BoardsDataStore } from './boards-data-store';
import { MainMenuManager } from '../../common/main-menu-manager';
import { ArduinoMenus, unregisterSubmenu } from '../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BoardsDataMenuUpdater implements FrontendApplicationContribution {

View File

@@ -5,7 +5,7 @@ import {
} from '../../common/protocol/boards-service';
import { ListWidget } from '../widgets/component-list/list-widget';
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BoardsListWidget extends ListWidget<BoardsPackage> {

View File

@@ -19,7 +19,7 @@ import { naturalCompare } from '../../common/utils';
import { NotificationCenter } from '../notification-center';
import { ArduinoCommands } from '../arduino-commands';
import { StorageWrapper } from '../storage-wrapper';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BoardsServiceProvider implements FrontendApplicationContribution {

View File

@@ -9,7 +9,7 @@ import {
BoardsServiceProvider,
AvailableBoard,
} from './boards-service-provider';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export interface BoardsDropDownListCoords {
readonly top: number;

View File

@@ -12,7 +12,7 @@ import {
} from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ConfigService } from '../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class About extends Contribution {

View File

@@ -9,7 +9,7 @@ import {
URI,
} from './contribution';
import { FileDialogService } from '@theia/filesystem/lib/browser';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class AddFile extends SketchContribution {

View File

@@ -15,7 +15,7 @@ import {
CommandRegistry,
MenuModelRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class AddZipLibrary extends SketchContribution {

View File

@@ -9,7 +9,7 @@ import {
CommandRegistry,
MenuModelRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class ArchiveSketch extends SketchContribution {

View File

@@ -23,7 +23,7 @@ import {
Port,
} from '../../common/protocol';
import { SketchContribution, Command, CommandRegistry } from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BoardSelection extends SketchContribution {

View File

@@ -1,5 +1,5 @@
import { inject, injectable } from 'inversify';
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
import { CoreService } from '../../common/protocol';
import { ArduinoMenus } from '../menu/arduino-menus';
import { BoardsDataStore } from '../boards/boards-data-store';
@@ -11,7 +11,7 @@ import {
CommandRegistry,
MenuModelRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class BurnBootloader extends SketchContribution {

View File

@@ -15,7 +15,7 @@ import {
KeybindingRegistry,
URI,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
/**
* Closes the `current` closeable editor, or any closeable current widget from the main area, or the current sketch window.

View File

@@ -9,7 +9,7 @@ import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
import { MessageService } from '@theia/core/lib/common/message-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
import {
MenuModelRegistry,
MenuContribution,
@@ -33,7 +33,7 @@ import {
CommandService,
} from '@theia/core/lib/common/command';
import { EditorMode } from '../editor-mode';
import { SettingsService } from '../settings';
import { SettingsService } from '../dialogs/settings/settings';
import { SketchesServiceClientImpl } from '../../common/protocol/sketches-service-client-impl';
import {
SketchesService,

View File

@@ -12,7 +12,7 @@ import {
SketchContribution,
TabBarToolbarRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class Debug extends SketchContribution {

View File

@@ -11,7 +11,7 @@ import {
CommandRegistry,
} from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
// TODO: [macOS]: to remove `Start Dictation...` and `Emoji & Symbol` see this thread: https://github.com/electron/electron/issues/8283#issuecomment-269522072
// Depends on https://github.com/eclipse-theia/theia/pull/7964

View File

@@ -22,7 +22,7 @@ import {
} from './contribution';
import { NotificationCenter } from '../notification-center';
import { Board, Sketch, SketchContainer } from '../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export abstract class Examples extends SketchContribution {

View File

@@ -12,7 +12,7 @@ import {
CommandRegistry,
KeybindingRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class Help extends Contribution {

View File

@@ -15,7 +15,7 @@ import { LibraryListWidget } from '../library/library-list-widget';
import { BoardsServiceProvider } from '../boards/boards-service-provider';
import { SketchContribution, Command, CommandRegistry } from './contribution';
import { NotificationCenter } from '../notification-center';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class IncludeLibrary extends SketchContribution {

View File

@@ -1,4 +1,4 @@
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import { injectable } from 'inversify';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';

View File

@@ -14,7 +14,7 @@ import { ArduinoMenus } from '../menu/arduino-menus';
import { MainMenuManager } from '../../common/main-menu-manager';
import { OpenSketch } from './open-sketch';
import { NotificationCenter } from '../notification-center';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class OpenRecentSketch extends SketchContribution {

View File

@@ -9,7 +9,7 @@ import {
MenuModelRegistry,
KeybindingRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class OpenSketchExternal extends SketchContribution {

View File

@@ -22,7 +22,7 @@ import { ExamplesService } from '../../common/protocol/examples-service';
import { BuiltInExamples } from './examples';
import { Sketchbook } from './sketchbook';
import { SketchContainer } from '../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class OpenSketch extends SketchContribution {

View File

@@ -9,7 +9,7 @@ import {
CommandRegistry,
} from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class QuitApp extends Contribution {

View File

@@ -10,7 +10,7 @@ import {
MenuModelRegistry,
KeybindingRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class SaveAsSketch extends SketchContribution {

View File

@@ -11,7 +11,7 @@ import {
KeybindingRegistry,
TabBarToolbarRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class SaveSketch extends SketchContribution {

View File

@@ -7,8 +7,9 @@ import {
KeybindingRegistry,
} from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { Settings as Preferences, SettingsDialog } from '../settings';
import { nls } from '@theia/core/lib/browser/nls';
import { Settings as Preferences } from '../dialogs/settings/settings';
import { SettingsDialog } from '../dialogs/settings/settings-dialog';
import { nls } from '@theia/core/lib/common';
@injectable()
export class Settings extends SketchContribution {

View File

@@ -21,7 +21,7 @@ import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus';
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
import { SketchesServiceClientImpl } from '../../common/protocol/sketches-service-client-impl';
import { LocalCacheFsProvider } from '../local-cache/local-cache-fs-provider';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class SketchControl extends SketchContribution {

View File

@@ -7,7 +7,7 @@ import { NotificationCenter } from '../notification-center';
import { Examples } from './examples';
import { SketchContainer } from '../../common/protocol';
import { OpenSketch } from './open-sketch';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class Sketchbook extends Examples {

View File

@@ -18,7 +18,7 @@ import {
certificateList,
} from '../dialogs/certificate-uploader/utils';
import { ArduinoFirmwareUploader } from '../../common/protocol/arduino-firmware-uploader';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class UploadCertificate extends Contribution {

View File

@@ -7,7 +7,7 @@ import {
} from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { UploadFirmwareDialog } from '../dialogs/firmware-uploader/firmware-uploader-dialog';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class UploadFirmware extends Contribution {

View File

@@ -15,8 +15,7 @@ import {
TabBarToolbarRegistry,
} from './contribution';
import { UserFieldsDialog } from '../dialogs/user-fields/user-fields-dialog';
import { nls } from '@theia/core/lib/browser/nls';
import { DisposableCollection } from '@theia/core';
import { DisposableCollection, nls } from '@theia/core/lib/common';
@injectable()
export class UploadSketch extends SketchContribution {

View File

@@ -13,7 +13,7 @@ import {
KeybindingRegistry,
TabBarToolbarRegistry,
} from './contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class VerifySketch extends SketchContribution {

View File

@@ -1,4 +1,4 @@
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import * as React from 'react';
export const CertificateAddComponent = ({

View File

@@ -4,7 +4,7 @@ import { AvailableBoard } from '../../boards/boards-service-provider';
import { CertificateListComponent } from './certificate-list';
import { SelectBoardComponent } from './select-board-components';
import { CertificateAddComponent } from './certificate-add-new';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export const CertificateUploaderComponent = ({
availableBoards,

View File

@@ -18,7 +18,7 @@ import {
import { CommandRegistry } from '@theia/core/lib/common/command';
import { certificateList, sanifyCertString } from './utils';
import { ArduinoFirmwareUploader } from '../../../common/protocol/arduino-firmware-uploader';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class UploadCertificateDialogWidget extends ReactWidget {

View File

@@ -1,4 +1,4 @@
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import * as React from 'react';
import { AvailableBoard } from '../../boards/boards-service-provider';
import { ArduinoSelect } from '../../widgets/arduino-select';

View File

@@ -6,7 +6,7 @@ import { clipboard } from 'electron';
import { ReactWidget, DialogProps } from '@theia/core/lib/browser';
import { AbstractDialog } from '../theia/dialogs/dialogs';
import { CreateApi } from '../create/create-api';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
const RadioButton = (props: {
id: string;

View File

@@ -6,7 +6,7 @@ import {
ConfirmDialogProps,
DialogError,
} from '@theia/core/lib/browser/dialogs';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class DoNotAskAgainDialogProps extends ConfirmDialogProps {

View File

@@ -1,4 +1,4 @@
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import * as React from 'react';
import {
ArduinoFirmwareUploader,

View File

@@ -1,324 +1,22 @@
import * as React from 'react';
import { injectable, inject, postConstruct } from 'inversify';
import { Widget } from '@phosphor/widgets';
import { Message } from '@phosphor/messaging';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import 'react-tabs/style/react-tabs.css';
import { Disable } from 'react-disable';
import URI from '@theia/core/lib/common/uri';
import { Emitter } from '@theia/core/lib/common/event';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { deepClone } from '@theia/core/lib/common/objects';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { ThemeService } from '@theia/core/lib/browser/theming';
import { MaybePromise } from '@theia/core/lib/common/types';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog/file-dialog-service';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
import {
DialogProps,
PreferenceService,
PreferenceScope,
DialogError,
ReactWidget,
} from '@theia/core/lib/browser';
import { Index } from '../common/types';
import {
CompilerWarnings,
CompilerWarningLiterals,
ConfigService,
FileSystemExt,
Network,
ProxySettings,
} from '../common/protocol';
import { AbstractDialog } from './theia/dialogs/dialogs';
import { nls } from '@theia/core/lib/browser/nls';
const EDITOR_SETTING = 'editor';
const FONT_SIZE_SETTING = `${EDITOR_SETTING}.fontSize`;
const AUTO_SAVE_SETTING = `${EDITOR_SETTING}.autoSave`;
const QUICK_SUGGESTIONS_SETTING = `${EDITOR_SETTING}.quickSuggestions`;
const ARDUINO_SETTING = 'arduino';
const WINDOW_SETTING = `${ARDUINO_SETTING}.window`;
// const IDE_SETTING = `${ARDUINO_SETTING}.ide`;
const COMPILE_SETTING = `${ARDUINO_SETTING}.compile`;
const UPLOAD_SETTING = `${ARDUINO_SETTING}.upload`;
const SKETCHBOOK_SETTING = `${ARDUINO_SETTING}.sketchbook`;
const AUTO_SCALE_SETTING = `${WINDOW_SETTING}.autoScale`;
const ZOOM_LEVEL_SETTING = `${WINDOW_SETTING}.zoomLevel`;
// const AUTO_UPDATE_SETTING = `${IDE_SETTING}.autoUpdate`;
const COMPILE_VERBOSE_SETTING = `${COMPILE_SETTING}.verbose`;
const COMPILE_WARNINGS_SETTING = `${COMPILE_SETTING}.warnings`;
const UPLOAD_VERBOSE_SETTING = `${UPLOAD_SETTING}.verbose`;
const UPLOAD_VERIFY_SETTING = `${UPLOAD_SETTING}.verify`;
const SHOW_ALL_FILES_SETTING = `${SKETCHBOOK_SETTING}.showAllFiles`;
export interface Settings extends Index {
editorFontSize: number; // `editor.fontSize`
themeId: string; // `workbench.colorTheme`
autoSave: 'on' | 'off'; // `editor.autoSave`
quickSuggestions: Record<'other' | 'comments' | 'strings', boolean>; // `editor.quickSuggestions`
autoScaleInterface: boolean; // `arduino.window.autoScale`
interfaceScale: number; // `arduino.window.zoomLevel` https://github.com/eclipse-theia/theia/issues/8751
checkForUpdates?: boolean; // `arduino.ide.autoUpdate`
verboseOnCompile: boolean; // `arduino.compile.verbose`
compilerWarnings: CompilerWarnings; // `arduino.compile.warnings`
verboseOnUpload: boolean; // `arduino.upload.verbose`
verifyAfterUpload: boolean; // `arduino.upload.verify`
sketchbookShowAllFiles: boolean; // `arduino.sketchbook.showAllFiles`
sketchbookPath: string; // CLI
additionalUrls: string[]; // CLI
network: Network; // CLI
}
export namespace Settings {
export function belongsToCli<K extends keyof Settings>(key: K): boolean {
return key === 'sketchbookPath' || key === 'additionalUrls';
}
}
@injectable()
export class SettingsService {
@inject(FileService)
protected readonly fileService: FileService;
@inject(FileSystemExt)
protected readonly fileSystemExt: FileSystemExt;
@inject(ConfigService)
protected readonly configService: ConfigService;
@inject(PreferenceService)
protected readonly preferenceService: PreferenceService;
@inject(FrontendApplicationStateService)
protected readonly appStateService: FrontendApplicationStateService;
protected readonly onDidChangeEmitter = new Emitter<Readonly<Settings>>();
readonly onDidChange = this.onDidChangeEmitter.event;
protected ready = new Deferred<void>();
protected _settings: Settings;
@postConstruct()
protected async init(): Promise<void> {
await this.appStateService.reachedState('ready'); // Hack for https://github.com/eclipse-theia/theia/issues/8993
const settings = await this.loadSettings();
this._settings = deepClone(settings);
this.ready.resolve();
}
protected async loadSettings(): Promise<Settings> {
await this.preferenceService.ready;
const [
editorFontSize,
themeId,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookShowAllFiles,
cliConfig,
] = await Promise.all([
this.preferenceService.get<number>(FONT_SIZE_SETTING, 12),
this.preferenceService.get<string>(
'workbench.colorTheme',
'arduino-theme'
),
this.preferenceService.get<'on' | 'off'>(AUTO_SAVE_SETTING, 'on'),
this.preferenceService.get<
Record<'other' | 'comments' | 'strings', boolean>
>(QUICK_SUGGESTIONS_SETTING, {
other: false,
comments: false,
strings: false,
}),
this.preferenceService.get<boolean>(AUTO_SCALE_SETTING, true),
this.preferenceService.get<number>(ZOOM_LEVEL_SETTING, 0),
// this.preferenceService.get<string>(AUTO_UPDATE_SETTING, true),
this.preferenceService.get<boolean>(COMPILE_VERBOSE_SETTING, true),
this.preferenceService.get<any>(COMPILE_WARNINGS_SETTING, 'None'),
this.preferenceService.get<boolean>(UPLOAD_VERBOSE_SETTING, true),
this.preferenceService.get<boolean>(UPLOAD_VERIFY_SETTING, true),
this.preferenceService.get<boolean>(SHOW_ALL_FILES_SETTING, false),
this.configService.getConfiguration(),
]);
const { additionalUrls, sketchDirUri, network } = cliConfig;
const sketchbookPath = await this.fileService.fsPath(new URI(sketchDirUri));
return {
editorFontSize,
themeId,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookShowAllFiles,
additionalUrls,
sketchbookPath,
network,
};
}
async settings(): Promise<Settings> {
await this.ready.promise;
return this._settings;
}
async update(settings: Settings, fireDidChange = false): Promise<void> {
await this.ready.promise;
for (const key of Object.keys(settings)) {
this._settings[key] = settings[key];
}
if (fireDidChange) {
this.onDidChangeEmitter.fire(this._settings);
}
}
async reset(): Promise<void> {
const settings = await this.loadSettings();
return this.update(settings, true);
}
async validate(
settings: MaybePromise<Settings> = this.settings()
): Promise<string | true> {
try {
const { sketchbookPath, editorFontSize, themeId } = await settings;
const sketchbookDir = await this.fileSystemExt.getUri(sketchbookPath);
if (!(await this.fileService.exists(new URI(sketchbookDir)))) {
return nls.localize(
'arduino/preferences/invalid.sketchbook.location',
'Invalid sketchbook location: {0}',
sketchbookPath
);
}
if (editorFontSize <= 0) {
return nls.localize(
'arduino/preferences/invalid.editorFontSize',
'Invalid editor font size. It must be a positive integer.'
);
}
if (
!ThemeService.get()
.getThemes()
.find(({ id }) => id === themeId)
) {
return nls.localize(
'arduino/preferences/invalid.theme',
'Invalid theme.'
);
}
return true;
} catch (err) {
if (err instanceof Error) {
return err.message;
}
return String(err);
}
}
async save(): Promise<string | true> {
await this.ready.promise;
const {
editorFontSize,
themeId,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookPath,
additionalUrls,
network,
sketchbookShowAllFiles,
} = this._settings;
const [config, sketchDirUri] = await Promise.all([
this.configService.getConfiguration(),
this.fileSystemExt.getUri(sketchbookPath),
]);
(config as any).additionalUrls = additionalUrls;
(config as any).sketchDirUri = sketchDirUri;
(config as any).network = network;
await Promise.all([
this.preferenceService.set(
'editor.fontSize',
editorFontSize,
PreferenceScope.User
),
this.preferenceService.set(
'workbench.colorTheme',
themeId,
PreferenceScope.User
),
this.preferenceService.set(
'editor.autoSave',
autoSave,
PreferenceScope.User
),
this.preferenceService.set(
'editor.quickSuggestions',
quickSuggestions,
PreferenceScope.User
),
this.preferenceService.set(
AUTO_SCALE_SETTING,
autoScaleInterface,
PreferenceScope.User
),
this.preferenceService.set(
ZOOM_LEVEL_SETTING,
interfaceScale,
PreferenceScope.User
),
// this.preferenceService.set(AUTO_UPDATE_SETTING, checkForUpdates, PreferenceScope.User),
this.preferenceService.set(
COMPILE_VERBOSE_SETTING,
verboseOnCompile,
PreferenceScope.User
),
this.preferenceService.set(
COMPILE_WARNINGS_SETTING,
compilerWarnings,
PreferenceScope.User
),
this.preferenceService.set(
UPLOAD_VERBOSE_SETTING,
verboseOnUpload,
PreferenceScope.User
),
this.preferenceService.set(
UPLOAD_VERIFY_SETTING,
verifyAfterUpload,
PreferenceScope.User
),
this.preferenceService.set(
SHOW_ALL_FILES_SETTING,
sketchbookShowAllFiles,
PreferenceScope.User
),
this.configService.setConfiguration(config),
]);
this.onDidChangeEmitter.fire(this._settings);
return true;
}
}
} from '../../../common/protocol';
import { nls } from '@theia/core/lib/common';
import { Settings, SettingsService } from './settings';
import { AdditionalUrlsDialog } from './settings-dialog';
import { AsyncLocalizationProvider } from '@theia/core/lib/common/i18n/localization';
export class SettingsComponent extends React.Component<
SettingsComponent.Props,
@@ -426,6 +124,12 @@ export class SettingsComponent extends React.Component<
'Theme'
) + ':'}
</div>
<div className="flex-line">
{nls.localize(
'vscode/editorStatus/status.editor.mode',
'Language'
) + ':'}
</div>
<div className="flex-line">
{nls.localize(
'arduino/preferences/showVerbose',
@@ -491,6 +195,27 @@ export class SettingsComponent extends React.Component<
))}
</select>
</div>
<div className="flex-line">
<select
className="theia-select"
value={this.state.currentLanguage}
onChange={this.languageDidChange}
>
{this.state.languages.map((label) => (
<option key={label} value={label}>
{label}
</option>
))}
</select>
<span style={{ marginLeft: '5px' }}>
(
{nls.localize(
'vscode/extensionsActions/reloadRequired',
'Reload required'
)}
)
</span>
</div>
<div className="flex-line">
<label className="flex-line">
<input
@@ -853,6 +578,13 @@ export class SettingsComponent extends React.Component<
}
};
protected languageDidChange = (
event: React.ChangeEvent<HTMLSelectElement>
) => {
const selectedLanguage = event.target.value;
this.setState({ currentLanguage: selectedLanguage });
};
protected compilerWarningsDidChange = (
event: React.ChangeEvent<HTMLSelectElement>
) => {
@@ -975,182 +707,7 @@ export namespace SettingsComponent {
readonly fileService: FileService;
readonly fileDialogService: FileDialogService;
readonly windowService: WindowService;
readonly localizationProvider: AsyncLocalizationProvider;
}
export type State = Settings;
}
@injectable()
export class SettingsWidget extends ReactWidget {
@inject(SettingsService)
protected readonly settingsService: SettingsService;
@inject(FileService)
protected readonly fileService: FileService;
@inject(FileDialogService)
protected readonly fileDialogService: FileDialogService;
@inject(WindowService)
protected readonly windowService: WindowService;
protected render(): React.ReactNode {
return (
<SettingsComponent
settingsService={this.settingsService}
fileService={this.fileService}
fileDialogService={this.fileDialogService}
windowService={this.windowService}
/>
);
}
}
@injectable()
export class SettingsDialogProps extends DialogProps {}
@injectable()
export class SettingsDialog extends AbstractDialog<Promise<Settings>> {
@inject(SettingsService)
protected readonly settingsService: SettingsService;
@inject(SettingsWidget)
protected readonly widget: SettingsWidget;
constructor(
@inject(SettingsDialogProps)
protected readonly props: SettingsDialogProps
) {
super(props);
this.contentNode.classList.add('arduino-settings-dialog');
this.appendCloseButton(
nls.localize('vscode/issueMainService/cancel', 'Cancel')
);
this.appendAcceptButton(nls.localize('vscode/issueMainService/ok', 'OK'));
}
@postConstruct()
protected init(): void {
this.toDispose.push(
this.settingsService.onDidChange(this.validate.bind(this))
);
}
protected async isValid(settings: Promise<Settings>): Promise<DialogError> {
const result = await this.settingsService.validate(settings);
if (typeof result === 'string') {
return result;
}
return '';
}
get value(): Promise<Settings> {
return this.settingsService.settings();
}
protected onAfterAttach(msg: Message): void {
if (this.widget.isAttached) {
Widget.detach(this.widget);
}
Widget.attach(this.widget, this.contentNode);
this.toDisposeOnDetach.push(
this.settingsService.onDidChange(() => this.update())
);
super.onAfterAttach(msg);
this.update();
}
protected onUpdateRequest(msg: Message) {
super.onUpdateRequest(msg);
this.widget.update();
}
protected onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
// calling settingsService.reset() in order to reload the settings from the preferenceService
// and update the UI including changes triggerd from the command palette
this.settingsService.reset();
this.widget.activate();
}
}
export class AdditionalUrlsDialog extends AbstractDialog<string[]> {
protected readonly textArea: HTMLTextAreaElement;
constructor(urls: string[], windowService: WindowService) {
super({
title: nls.localize(
'arduino/preferences/additionalManagerURLs',
'Additional Boards Manager URLs'
),
});
this.contentNode.classList.add('additional-urls-dialog');
const description = document.createElement('div');
description.textContent = nls.localize(
'arduino/preferences/enterAdditionalURLs',
'Enter additional URLs, one for each row'
);
description.style.marginBottom = '5px';
this.contentNode.appendChild(description);
this.textArea = document.createElement('textarea');
this.textArea.className = 'theia-input';
this.textArea.setAttribute('style', 'flex: 0;');
this.textArea.value = urls
.filter((url) => url.trim())
.filter((url) => !!url)
.join('\n');
this.textArea.wrap = 'soft';
this.textArea.cols = 90;
this.textArea.rows = 5;
this.contentNode.appendChild(this.textArea);
const anchor = document.createElement('div');
anchor.classList.add('link');
anchor.textContent = nls.localize(
'arduino/preferences/unofficialBoardSupport',
'Click for a list of unofficial board support URLs'
);
anchor.style.marginTop = '5px';
anchor.style.cursor = 'pointer';
this.addEventListener(anchor, 'click', () =>
windowService.openNewWindow(
'https://github.com/arduino/Arduino/wiki/Unofficial-list-of-3rd-party-boards-support-urls',
{ external: true }
)
);
this.contentNode.appendChild(anchor);
this.appendAcceptButton(nls.localize('vscode/issueMainService/ok', 'OK'));
this.appendCloseButton(
nls.localize('vscode/issueMainService/cancel', 'Cancel')
);
}
get value(): string[] {
return this.textArea.value
.split('\n')
.map((url) => url.trim())
.filter((url) => !!url);
}
protected onAfterAttach(message: Message): void {
super.onAfterAttach(message);
this.addUpdateListener(this.textArea, 'input');
}
protected onActivateRequest(message: Message): void {
super.onActivateRequest(message);
this.textArea.focus();
}
protected handleEnter(event: KeyboardEvent): boolean | void {
if (event.target instanceof HTMLInputElement) {
return super.handleEnter(event);
}
return false;
}
export type State = Settings & { languages: string[] };
}

View File

@@ -0,0 +1,193 @@
import * as React from 'react';
import { injectable, inject, postConstruct } from 'inversify';
import { Widget } from '@phosphor/widgets';
import { Message } from '@phosphor/messaging';
import { DialogError, ReactWidget } from '@theia/core/lib/browser';
import { AbstractDialog, DialogProps } from '@theia/core/lib/browser';
import { Settings, SettingsService } from './settings';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog/file-dialog-service';
import { nls } from '@theia/core/lib/common';
import { SettingsComponent } from './settings-component';
import { AsyncLocalizationProvider } from '@theia/core/lib/common/i18n/localization';
@injectable()
export class SettingsWidget extends ReactWidget {
@inject(SettingsService)
protected readonly settingsService: SettingsService;
@inject(FileService)
protected readonly fileService: FileService;
@inject(FileDialogService)
protected readonly fileDialogService: FileDialogService;
@inject(WindowService)
protected readonly windowService: WindowService;
@inject(AsyncLocalizationProvider)
protected readonly localizationProvider: AsyncLocalizationProvider;
protected render(): React.ReactNode {
return (
<SettingsComponent
settingsService={this.settingsService}
fileService={this.fileService}
fileDialogService={this.fileDialogService}
windowService={this.windowService}
localizationProvider={this.localizationProvider}
/>
);
}
}
@injectable()
export class SettingsDialogProps extends DialogProps {}
@injectable()
export class SettingsDialog extends AbstractDialog<Promise<Settings>> {
@inject(SettingsService)
protected readonly settingsService: SettingsService;
@inject(SettingsWidget)
protected readonly widget: SettingsWidget;
constructor(
@inject(SettingsDialogProps)
protected readonly props: SettingsDialogProps
) {
super(props);
this.contentNode.classList.add('arduino-settings-dialog');
this.appendCloseButton(
nls.localize('vscode/issueMainService/cancel', 'Cancel')
);
this.appendAcceptButton(nls.localize('vscode/issueMainService/ok', 'OK'));
}
@postConstruct()
protected init(): void {
this.toDispose.push(
this.settingsService.onDidChange(this.validate.bind(this))
);
}
protected async isValid(settings: Promise<Settings>): Promise<DialogError> {
const result = await this.settingsService.validate(settings);
if (typeof result === 'string') {
return result;
}
return '';
}
get value(): Promise<Settings> {
return this.settingsService.settings();
}
protected onAfterAttach(msg: Message): void {
if (this.widget.isAttached) {
Widget.detach(this.widget);
}
Widget.attach(this.widget, this.contentNode);
this.toDisposeOnDetach.push(
this.settingsService.onDidChange(() => this.update())
);
super.onAfterAttach(msg);
this.update();
}
protected onUpdateRequest(msg: Message) {
super.onUpdateRequest(msg);
this.widget.update();
}
protected onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
// calling settingsService.reset() in order to reload the settings from the preferenceService
// and update the UI including changes triggerd from the command palette
this.settingsService.reset();
this.widget.activate();
}
}
export class AdditionalUrlsDialog extends AbstractDialog<string[]> {
protected readonly textArea: HTMLTextAreaElement;
constructor(urls: string[], windowService: WindowService) {
super({
title: nls.localize(
'arduino/preferences/additionalManagerURLs',
'Additional Boards Manager URLs'
),
});
this.contentNode.classList.add('additional-urls-dialog');
const description = document.createElement('div');
description.textContent = nls.localize(
'arduino/preferences/enterAdditionalURLs',
'Enter additional URLs, one for each row'
);
description.style.marginBottom = '5px';
this.contentNode.appendChild(description);
this.textArea = document.createElement('textarea');
this.textArea.className = 'theia-input';
this.textArea.setAttribute('style', 'flex: 0;');
this.textArea.value = urls
.filter((url) => url.trim())
.filter((url) => !!url)
.join('\n');
this.textArea.wrap = 'soft';
this.textArea.cols = 90;
this.textArea.rows = 5;
this.contentNode.appendChild(this.textArea);
const anchor = document.createElement('div');
anchor.classList.add('link');
anchor.textContent = nls.localize(
'arduino/preferences/unofficialBoardSupport',
'Click for a list of unofficial board support URLs'
);
anchor.style.marginTop = '5px';
anchor.style.cursor = 'pointer';
this.addEventListener(anchor, 'click', () =>
windowService.openNewWindow(
'https://github.com/arduino/Arduino/wiki/Unofficial-list-of-3rd-party-boards-support-urls',
{ external: true }
)
);
this.contentNode.appendChild(anchor);
this.appendAcceptButton(nls.localize('vscode/issueMainService/ok', 'OK'));
this.appendCloseButton(
nls.localize('vscode/issueMainService/cancel', 'Cancel')
);
}
get value(): string[] {
return this.textArea.value
.split('\n')
.map((url) => url.trim())
.filter((url) => !!url);
}
protected onAfterAttach(message: Message): void {
super.onAfterAttach(message);
this.addUpdateListener(this.textArea, 'input');
}
protected onActivateRequest(message: Message): void {
super.onActivateRequest(message);
this.textArea.focus();
}
protected handleEnter(event: KeyboardEvent): boolean | void {
if (event.target instanceof HTMLInputElement) {
return super.handleEnter(event);
}
return false;
}
}

View File

@@ -0,0 +1,325 @@
import { injectable, inject, postConstruct } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { Emitter } from '@theia/core/lib/common/event';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { deepClone } from '@theia/core/lib/common/objects';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { ThemeService } from '@theia/core/lib/browser/theming';
import { MaybePromise } from '@theia/core/lib/common/types';
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
import { PreferenceService, PreferenceScope } from '@theia/core/lib/browser';
import { Index } from '../../../common/types';
import {
CompilerWarnings,
ConfigService,
FileSystemExt,
Network,
} from '../../../common/protocol';
import { nls } from '@theia/core/lib/common';
import { AsyncLocalizationProvider } from '@theia/core/lib/common/i18n/localization';
const EDITOR_SETTING = 'editor';
const FONT_SIZE_SETTING = `${EDITOR_SETTING}.fontSize`;
const AUTO_SAVE_SETTING = `${EDITOR_SETTING}.autoSave`;
const QUICK_SUGGESTIONS_SETTING = `${EDITOR_SETTING}.quickSuggestions`;
const ARDUINO_SETTING = 'arduino';
const WINDOW_SETTING = `${ARDUINO_SETTING}.window`;
// const IDE_SETTING = `${ARDUINO_SETTING}.ide`;
const COMPILE_SETTING = `${ARDUINO_SETTING}.compile`;
const UPLOAD_SETTING = `${ARDUINO_SETTING}.upload`;
const SKETCHBOOK_SETTING = `${ARDUINO_SETTING}.sketchbook`;
const AUTO_SCALE_SETTING = `${WINDOW_SETTING}.autoScale`;
const ZOOM_LEVEL_SETTING = `${WINDOW_SETTING}.zoomLevel`;
// const AUTO_UPDATE_SETTING = `${IDE_SETTING}.autoUpdate`;
const COMPILE_VERBOSE_SETTING = `${COMPILE_SETTING}.verbose`;
const COMPILE_WARNINGS_SETTING = `${COMPILE_SETTING}.warnings`;
const UPLOAD_VERBOSE_SETTING = `${UPLOAD_SETTING}.verbose`;
const UPLOAD_VERIFY_SETTING = `${UPLOAD_SETTING}.verify`;
const SHOW_ALL_FILES_SETTING = `${SKETCHBOOK_SETTING}.showAllFiles`;
export interface Settings extends Index {
editorFontSize: number; // `editor.fontSize`
themeId: string; // `workbench.colorTheme`
autoSave: 'on' | 'off'; // `editor.autoSave`
quickSuggestions: Record<'other' | 'comments' | 'strings', boolean>; // `editor.quickSuggestions`
languages: string[]; // `languages from the plugins`
currentLanguage: string;
autoScaleInterface: boolean; // `arduino.window.autoScale`
interfaceScale: number; // `arduino.window.zoomLevel` https://github.com/eclipse-theia/theia/issues/8751
checkForUpdates?: boolean; // `arduino.ide.autoUpdate`
verboseOnCompile: boolean; // `arduino.compile.verbose`
compilerWarnings: CompilerWarnings; // `arduino.compile.warnings`
verboseOnUpload: boolean; // `arduino.upload.verbose`
verifyAfterUpload: boolean; // `arduino.upload.verify`
sketchbookShowAllFiles: boolean; // `arduino.sketchbook.showAllFiles`
sketchbookPath: string; // CLI
additionalUrls: string[]; // CLI
network: Network; // CLI
}
export namespace Settings {
export function belongsToCli<K extends keyof Settings>(key: K): boolean {
return key === 'sketchbookPath' || key === 'additionalUrls';
}
}
@injectable()
export class SettingsService {
@inject(FileService)
protected readonly fileService: FileService;
@inject(FileSystemExt)
protected readonly fileSystemExt: FileSystemExt;
@inject(ConfigService)
protected readonly configService: ConfigService;
@inject(PreferenceService)
protected readonly preferenceService: PreferenceService;
@inject(FrontendApplicationStateService)
protected readonly appStateService: FrontendApplicationStateService;
@inject(AsyncLocalizationProvider)
protected readonly localizationProvider: AsyncLocalizationProvider;
protected readonly onDidChangeEmitter = new Emitter<Readonly<Settings>>();
readonly onDidChange = this.onDidChangeEmitter.event;
protected ready = new Deferred<void>();
protected _settings: Settings;
@postConstruct()
protected async init(): Promise<void> {
await this.appStateService.reachedState('ready'); // Hack for https://github.com/eclipse-theia/theia/issues/8993
const settings = await this.loadSettings();
this._settings = deepClone(settings);
this.ready.resolve();
}
protected async loadSettings(): Promise<Settings> {
await this.preferenceService.ready;
const [
languages,
currentLanguage,
editorFontSize,
themeId,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookShowAllFiles,
cliConfig,
] = await Promise.all([
['en', ...(await this.localizationProvider.getAvailableLanguages())],
this.localizationProvider.getCurrentLanguage(),
this.preferenceService.get<number>(FONT_SIZE_SETTING, 12),
this.preferenceService.get<string>(
'workbench.colorTheme',
'arduino-theme'
),
this.preferenceService.get<'on' | 'off'>(AUTO_SAVE_SETTING, 'on'),
this.preferenceService.get<
Record<'other' | 'comments' | 'strings', boolean>
>(QUICK_SUGGESTIONS_SETTING, {
other: false,
comments: false,
strings: false,
}),
this.preferenceService.get<boolean>(AUTO_SCALE_SETTING, true),
this.preferenceService.get<number>(ZOOM_LEVEL_SETTING, 0),
// this.preferenceService.get<string>(AUTO_UPDATE_SETTING, true),
this.preferenceService.get<boolean>(COMPILE_VERBOSE_SETTING, true),
this.preferenceService.get<any>(COMPILE_WARNINGS_SETTING, 'None'),
this.preferenceService.get<boolean>(UPLOAD_VERBOSE_SETTING, true),
this.preferenceService.get<boolean>(UPLOAD_VERIFY_SETTING, true),
this.preferenceService.get<boolean>(SHOW_ALL_FILES_SETTING, false),
this.configService.getConfiguration(),
]);
const { additionalUrls, sketchDirUri, network } = cliConfig;
const sketchbookPath = await this.fileService.fsPath(new URI(sketchDirUri));
return {
editorFontSize,
themeId,
languages,
currentLanguage,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookShowAllFiles,
additionalUrls,
sketchbookPath,
network,
};
}
async settings(): Promise<Settings> {
await this.ready.promise;
return this._settings;
}
async update(settings: Settings, fireDidChange = false): Promise<void> {
await this.ready.promise;
for (const key of Object.keys(settings)) {
this._settings[key] = settings[key];
}
if (fireDidChange) {
this.onDidChangeEmitter.fire(this._settings);
}
}
async reset(): Promise<void> {
const settings = await this.loadSettings();
return this.update(settings, true);
}
async validate(
settings: MaybePromise<Settings> = this.settings()
): Promise<string | true> {
try {
const { sketchbookPath, editorFontSize, themeId } = await settings;
const sketchbookDir = await this.fileSystemExt.getUri(sketchbookPath);
if (!(await this.fileService.exists(new URI(sketchbookDir)))) {
return nls.localize(
'arduino/preferences/invalid.sketchbook.location',
'Invalid sketchbook location: {0}',
sketchbookPath
);
}
if (editorFontSize <= 0) {
return nls.localize(
'arduino/preferences/invalid.editorFontSize',
'Invalid editor font size. It must be a positive integer.'
);
}
if (
!ThemeService.get()
.getThemes()
.find(({ id }) => id === themeId)
) {
return nls.localize(
'arduino/preferences/invalid.theme',
'Invalid theme.'
);
}
return true;
} catch (err) {
if (err instanceof Error) {
return err.message;
}
return String(err);
}
}
async save(): Promise<string | true> {
await this.ready.promise;
const {
currentLanguage,
editorFontSize,
themeId,
autoSave,
quickSuggestions,
autoScaleInterface,
interfaceScale,
// checkForUpdates,
verboseOnCompile,
compilerWarnings,
verboseOnUpload,
verifyAfterUpload,
sketchbookPath,
additionalUrls,
network,
sketchbookShowAllFiles,
} = this._settings;
const [config, sketchDirUri] = await Promise.all([
this.configService.getConfiguration(),
this.fileSystemExt.getUri(sketchbookPath),
]);
(config as any).additionalUrls = additionalUrls;
(config as any).sketchDirUri = sketchDirUri;
(config as any).network = network;
(config as any).locale = currentLanguage;
await Promise.all([
this.preferenceService.set(
'editor.fontSize',
editorFontSize,
PreferenceScope.User
),
this.preferenceService.set(
'workbench.colorTheme',
themeId,
PreferenceScope.User
),
this.preferenceService.set(
'editor.autoSave',
autoSave,
PreferenceScope.User
),
this.preferenceService.set(
'editor.quickSuggestions',
quickSuggestions,
PreferenceScope.User
),
this.preferenceService.set(
AUTO_SCALE_SETTING,
autoScaleInterface,
PreferenceScope.User
),
this.preferenceService.set(
ZOOM_LEVEL_SETTING,
interfaceScale,
PreferenceScope.User
),
// this.preferenceService.set(AUTO_UPDATE_SETTING, checkForUpdates, PreferenceScope.User),
this.preferenceService.set(
COMPILE_VERBOSE_SETTING,
verboseOnCompile,
PreferenceScope.User
),
this.preferenceService.set(
COMPILE_WARNINGS_SETTING,
compilerWarnings,
PreferenceScope.User
),
this.preferenceService.set(
UPLOAD_VERBOSE_SETTING,
verboseOnUpload,
PreferenceScope.User
),
this.preferenceService.set(
UPLOAD_VERIFY_SETTING,
verifyAfterUpload,
PreferenceScope.User
),
this.preferenceService.set(
SHOW_ALL_FILES_SETTING,
sketchbookShowAllFiles,
PreferenceScope.User
),
this.configService.setConfiguration(config),
]);
this.onDidChangeEmitter.fire(this._settings);
// after saving all the settings, if we need to change the language we need to perform a reload
if (currentLanguage !== nls.locale) {
window.localStorage.setItem(nls.localeId, currentLanguage);
window.location.reload();
}
return true;
}
}

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { BoardUserField } from '../../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export const UserFieldsComponent = ({
initialBoardUserFields,

View File

@@ -10,7 +10,7 @@ import {
import { ListWidget } from '../widgets/component-list/list-widget';
import { Installable } from '../../common/protocol';
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class LibraryListWidget extends ListWidget<LibraryPackage> {

View File

@@ -4,7 +4,7 @@ import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-con
import { MenuModelRegistry } from '@theia/core';
import { LibraryListWidget } from './library-list-widget';
import { ArduinoMenus } from '../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class LibraryListWidgetFrontendContribution

View File

@@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify';
import { Emitter } from '@theia/core/lib/common/event';
import { OutputContribution } from '@theia/output/lib/browser/output-contribution';
import { OutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager } from '@theia/output/lib/browser/output-channel';
import {
OutputMessage,
ProgressMessage,

View File

@@ -10,7 +10,7 @@ import {
import { ArduinoToolbar } from '../../toolbar/arduino-toolbar';
import { SerialModel } from '../serial-model';
import { ArduinoMenus } from '../../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export namespace SerialMonitor {
export namespace Commands {

View File

@@ -15,8 +15,8 @@ import { SerialModel } from '../serial-model';
import { Serial, SerialConnectionManager } from '../serial-connection-manager';
import { SerialMonitorSendInput } from './serial-monitor-send-input';
import { SerialMonitorOutput } from './serial-monitor-send-output';
import { nls } from '@theia/core/lib/browser/nls';
import { BoardsServiceProvider } from '../../boards/boards-service-provider';
import { nls } from '@theia/core/lib/common';
@injectable()
export class MonitorWidget extends ReactWidget {

View File

@@ -3,7 +3,7 @@ import { Key, KeyCode } from '@theia/core/lib/browser/keys';
import { Board, Port } from '../../../common/protocol/boards-service';
import { SerialConfig } from '../../../common/protocol/serial-service';
import { isOSX } from '@theia/core/lib/common/os';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export namespace SerialMonitorSendInput {
export interface Props {

View File

@@ -18,8 +18,8 @@ import {
import { BoardsConfig } from '../boards/boards-config';
import { SerialModel } from './serial-model';
import { ThemeService } from '@theia/core/lib/browser/theming';
import { nls } from '@theia/core/lib/browser/nls';
import { CoreService } from '../../common/protocol';
import { nls } from '@theia/core/lib/common/nls';
@injectable()
export class SerialConnectionManager {

View File

@@ -15,7 +15,7 @@ import {
import { Sketch } from '../../../common/protocol';
import { SaveAsSketch } from '../../contributions/save-as-sketch';
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class ApplicationShell extends TheiaApplicationShell {

View File

@@ -4,9 +4,18 @@ import {
CommonFrontendContribution as TheiaCommonFrontendContribution,
CommonCommands,
} from '@theia/core/lib/browser/common-frontend-contribution';
import { CommandRegistry } from '@theia/core/lib/common/command';
@injectable()
export class CommonFrontendContribution extends TheiaCommonFrontendContribution {
registerCommands(commandRegistry: CommandRegistry): void {
super.registerCommands(commandRegistry);
for (const command of [CommonCommands.CONFIGURE_DISPLAY_LANGUAGE]) {
commandRegistry.unregisterCommand(command);
}
}
registerMenus(registry: MenuModelRegistry): void {
super.registerMenus(registry);
for (const command of [

View File

@@ -8,7 +8,7 @@ import {
} from '@theia/core/lib/browser/connection-status-service';
import { ArduinoDaemon } from '../../../common/protocol';
import { NotificationCenter } from '../../notification-center';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService {

View File

@@ -3,7 +3,7 @@ import { DebugError } from '@theia/debug/lib/common/debug-service';
import { DebugSession } from '@theia/debug/lib/browser/debug-session';
import { DebugSessionOptions } from '@theia/debug/lib/browser/debug-session-options';
import { DebugSessionManager as TheiaDebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class DebugSessionManager extends TheiaDebugSessionManager {

View File

@@ -5,7 +5,7 @@ import { LabelProvider } from '@theia/core/lib/browser';
import { EditorWidgetFactory as TheiaEditorWidgetFactory } from '@theia/editor/lib/browser/editor-widget-factory';
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
import { SketchesService, Sketch } from '../../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class EditorWidgetFactory extends TheiaEditorWidgetFactory {

View File

@@ -5,7 +5,7 @@ import {
KeymapsCommands,
} from '@theia/keymaps/lib/browser/keymaps-frontend-contribution';
import { ArduinoMenus } from '../../menu/arduino-menus';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class KeymapsFrontendContribution extends TheiaKeymapsFrontendContribution {

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { NotificationComponent } from './notification-component';
import { NotificationCenterComponent as TheiaNotificationCenterComponent } from '@theia/messages/lib/browser/notification-center-component';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
const PerfectScrollbar = require('react-perfect-scrollbar');

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { NotificationComponent as TheiaNotificationComponent } from '@theia/messages/lib/browser/notification-component';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export class NotificationComponent extends TheiaNotificationComponent {
render(): React.ReactNode {

View File

@@ -7,7 +7,7 @@ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model
import {
OutputChannelManager as TheiaOutputChannelManager,
OutputChannel as TheiaOutputChannel,
} from '@theia/output/lib/common/output-channel';
} from '@theia/output/lib/browser/output-channel';
@injectable()
export class OutputChannelManager extends TheiaOutputChannelManager {

View File

@@ -0,0 +1,19 @@
import { ViewContainer } from '@theia/core/lib/browser/view-container';
import { injectable } from '@theia/core/shared/inversify';
import {
SearchInWorkspaceFactory as TheiaSearchInWorkspaceFactory,
SEARCH_VIEW_CONTAINER_TITLE_OPTIONS,
} from '@theia/search-in-workspace/lib/browser/search-in-workspace-factory';
@injectable()
export class SearchInWorkspaceFactory extends TheiaSearchInWorkspaceFactory {
async createWidget(): Promise<ViewContainer> {
const viewContainer = await super.createWidget();
viewContainer.setTitleOptions({
...SEARCH_VIEW_CONTAINER_TITLE_OPTIONS,
iconClass: 'fa fa-arduino-search',
});
return viewContainer;
}
}

View File

@@ -15,7 +15,7 @@ import { WorkspaceInputDialog } from './workspace-input-dialog';
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
import { SaveAsSketch } from '../../contributions/save-as-sketch';
import { SingleTextInputDialog } from '@theia/core/lib/browser';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribution {

View File

@@ -3,7 +3,7 @@ import { remote } from 'electron';
import URI from '@theia/core/lib/common/uri';
import { WorkspaceDeleteHandler as TheiaWorkspaceDeleteHandler } from '@theia/workspace/lib/browser/workspace-delete-handler';
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class WorkspaceDeleteHandler extends TheiaWorkspaceDeleteHandler {

View File

@@ -6,7 +6,7 @@ import {
WorkspaceInputDialog as TheiaWorkspaceInputDialog,
WorkspaceInputDialogProps,
} from '@theia/workspace/lib/browser/workspace-input-dialog';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export class WorkspaceInputDialog extends TheiaWorkspaceInputDialog {
protected wasTouched = false;

View File

@@ -17,7 +17,7 @@ import {
import { ArduinoWorkspaceRootResolver } from '../../arduino-workspace-resolver';
import { BoardsServiceProvider } from '../../boards/boards-service-provider';
import { BoardsConfig } from '../../boards/boards-config';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class WorkspaceService extends TheiaWorkspaceService {

View File

@@ -9,7 +9,7 @@ import { UserStatus } from './cloud-user-status';
import { CloudSketchbookTreeWidget } from './cloud-sketchbook-tree-widget';
import { AuthenticationClientService } from '../../auth/authentication-client-service';
import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class CloudSketchbookCompositeWidget extends BaseWidget {

View File

@@ -27,7 +27,7 @@ import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-ser
import { Contribution } from '../../contributions/contribution';
import { ArduinoPreferences } from '../../arduino-preferences';
import { MainMenuManager } from '../../../common/main-menu-manager';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export const SKETCHBOOKSYNC__CONTEXT = ['arduino-sketchbook-sync--context'];

View File

@@ -14,7 +14,7 @@ import { FileService } from '@theia/filesystem/lib/browser/file-service';
import URI from '@theia/core/lib/common/uri';
import { SketchCache } from './cloud-sketch-cache';
import { Create } from '../../create/typings';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export function sketchBaseDir(sketch: Create.Sketch): FileStat {
// extract the sketch path

View File

@@ -11,7 +11,7 @@ import { TreeNode } from '@theia/core/lib/browser/tree';
import { CompositeTreeNode } from '@theia/core/lib/browser';
import { shell } from 'electron';
import { SketchbookTreeWidget } from '../sketchbook/sketchbook-tree-widget';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
const LEARN_MORE_URL =
'https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-cloud-sketch-sync';

View File

@@ -34,7 +34,7 @@ import { FileStat } from '@theia/filesystem/lib/common/files';
import { WorkspaceNode } from '@theia/navigator/lib/browser/navigator-tree';
import { posix, splitSketchPath } from '../../create/create-paths';
import { Create } from '../../create/typings';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
const MESSAGE_TIMEOUT = 5 * 1000;
const deepmerge = require('deepmerge').default;

View File

@@ -7,7 +7,7 @@ import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model';
import { AuthenticationClientService } from '../../auth/authentication-client-service';
import { CloudUserCommands } from '../../auth/cloud-user-commands';
import { AuthenticationSessionAccountInformation } from '../../../common/protocol/authentication-service';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export class UserStatus extends React.Component<
UserStatus.Props,

View File

@@ -12,7 +12,7 @@ import { ListWidget } from './list-widget';
import { ComponentList } from './component-list';
import { ListItemRenderer } from './list-item-renderer';
import { ResponseServiceArduino } from '../../../common/protocol';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
export class FilterableListContainer<
T extends ArduinoComponent

View File

@@ -4,7 +4,7 @@ import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { Installable } from '../../../common/protocol/installable';
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
import { ComponentListItem } from './component-list-item';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class ListItemRenderer<T extends ArduinoComponent> {

View File

@@ -1,4 +1,4 @@
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
import * as React from 'react';
export class SearchBar extends React.Component<SearchBar.Props> {

View File

@@ -17,7 +17,7 @@ import { ArduinoPreferences } from '../../arduino-preferences';
import { SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
import { SelectableTreeNode } from '@theia/core/lib/browser/tree/tree-selection';
import { Sketch } from '../../contributions/contribution';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class SketchbookTreeWidget extends FileTreeWidget {

View File

@@ -6,7 +6,7 @@ import { Message, MessageLoop } from '@phosphor/messaging';
import { Disposable } from '@theia/core/lib/common/disposable';
import { BaseWidget } from '@theia/core/lib/browser/widgets/widget';
import { SketchbookTreeWidget } from './sketchbook-tree-widget';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class SketchbookWidget extends BaseWidget {

View File

@@ -1,3 +1,5 @@
import { RecursivePartial } from '@theia/core/lib/common/types';
export const ConfigServicePath = '/services/config-service';
export const ConfigService = Symbol('ConfigService');
export interface ConfigService {
@@ -11,6 +13,29 @@ export interface ConfigService {
isInSketchDir(uri: string): Promise<boolean>;
}
export interface Daemon {
readonly port: string | number;
}
export namespace Daemon {
export function is(
daemon: RecursivePartial<Daemon> | undefined
): daemon is Daemon {
return !!daemon && !!daemon.port;
}
export function sameAs(
left: RecursivePartial<Daemon> | undefined,
right: RecursivePartial<Daemon> | undefined
): boolean {
if (left === undefined) {
return right === undefined;
}
if (right === undefined) {
return left === undefined;
}
return String(left.port) === String(right.port);
}
}
export interface ProxySettings {
protocol: string;
hostname: string;
@@ -87,11 +112,13 @@ export namespace Network {
}
export interface Config {
readonly locale: string;
readonly sketchDirUri: string;
readonly dataDirUri: string;
readonly downloadsDirUri: string;
readonly additionalUrls: string[];
readonly network: Network;
readonly daemon: Daemon;
}
export namespace Config {
export function sameAs(left: Config, right: Config): boolean {
@@ -106,6 +133,7 @@ export namespace Config {
}
}
return (
left.locale === right.locale &&
left.dataDirUri === right.dataDirUri &&
left.downloadsDirUri === right.downloadsDirUri &&
left.sketchDirUri === right.sketchDirUri &&

View File

@@ -7,7 +7,7 @@ import {
} from '@theia/core/lib/browser/connection-status-service';
import { ElectronWindowService as TheiaElectronWindowService } from '@theia/core/lib/electron-browser/window/electron-window-service';
import { SplashService } from '../electron-common/splash-service';
import { nls } from '@theia/core/lib/browser/nls';
import { nls } from '@theia/core/lib/common';
@injectable()
export class ElectronWindowService extends TheiaElectronWindowService {

View File

@@ -15,10 +15,11 @@ import {
ArduinoMenus,
PlaceholderMenuNode,
} from '../../../browser/menu/arduino-menus';
import electron = require('@theia/core/shared/electron');
@injectable()
export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
createMenuBar(): Electron.Menu {
createElectronMenuBar(): Electron.Menu {
this._toggledCommands.clear(); // https://github.com/eclipse-theia/theia/issues/8977
const menuModel = this.menuProvider.getMenu(MAIN_MENU_BAR);
const template = this.fillMenuTemplate([], menuModel);
@@ -30,7 +31,17 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
return menu;
}
createContextMenu(menuPath: MenuPath, args?: any[]): Electron.Menu {
async setMenuBar(): Promise<void> {
await this.preferencesService.ready;
const createdMenuBar = this.createElectronMenuBar();
if (isOSX) {
electron.remote.Menu.setApplicationMenu(createdMenuBar);
} else {
electron.remote.getCurrentWindow().setMenu(createdMenuBar);
}
}
createElectronContextMenu(menuPath: MenuPath, args?: any[]): Electron.Menu {
const menuModel = this.menuProvider.getMenu(menuPath);
const template = this.fillMenuTemplate([], menuModel, args, {
showDisabled: false,
@@ -99,7 +110,7 @@ export class ElectronMainMenuFactory extends TheiaElectronMainMenuFactory {
return { label, submenu };
}
protected handleDefault(
protected handleElectronDefault(
menuNode: CompositeMenuNode,
args: any[] = [],
options?: ElectronMenuOptions

View File

@@ -17,6 +17,7 @@ import {
TheiaBrowserWindowOptions,
} from '@theia/core/lib/electron-main/electron-main-application';
import { SplashServiceImpl } from '../splash/splash-service-impl';
import { ipcMain } from '@theia/core/shared/electron';
app.commandLine.appendSwitch('disable-http-cache');
@@ -35,6 +36,20 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
return super.start(config);
}
protected getTitleBarStyle(): 'native' | 'custom' {
return 'native';
}
protected hookApplicationEvents(): void {
app.on('will-quit', this.onWillQuit.bind(this));
app.on('second-instance', this.onSecondInstance.bind(this));
app.on('window-all-closed', this.onWindowAllClosed.bind(this));
ipcMain.on('restart', ({ sender }) => {
this.restart(sender.id);
});
}
/**
* Use this rather than creating `BrowserWindow` instances from scratch, since some security parameters need to be set, this method will do it.
*

View File

@@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify';
import { NewWindowOptions } from '@theia/core/lib/browser/window/window-service';
import { ElectronMainWindowServiceImpl as TheiaElectronMainWindowService } from '@theia/core/lib/electron-main/electron-main-window-service-impl';
import { ElectronMainApplication } from './electron-main-application';
import { NewWindowOptions } from '@theia/core/lib/common/window';
@injectable()
export class ElectronMainWindowServiceImpl extends TheiaElectronMainWindowService {

View File

@@ -12,6 +12,7 @@ import { Event, Emitter } from '@theia/core/lib/common/event';
import { environment } from '@theia/application-package/lib/environment';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
import { LocalizationProvider } from '@theia/core/lib/node/i18n/localization-provider';
import { ArduinoDaemon, NotificationServiceServer } from '../common/protocol';
import { DaemonLog } from './daemon-log';
import { CLI_CONFIG } from './cli-config';
@@ -31,6 +32,9 @@ export class ArduinoDaemonImpl
@inject(NotificationServiceServer)
protected readonly notificationService: NotificationServiceServer;
@inject(LocalizationProvider)
protected readonly localizationProvider: LocalizationProvider;
protected readonly toDispose = new DisposableCollection();
protected readonly onDaemonStartedEmitter = new Emitter<void>();
protected readonly onDaemonStoppedEmitter = new Emitter<void>();

View File

@@ -1,4 +1,5 @@
import { RecursivePartial } from '@theia/core/lib/common/types';
import { Daemon } from '../common/protocol/config-service';
export const CLI_CONFIG = 'arduino-cli.yaml';
@@ -21,29 +22,6 @@ export namespace BoardManager {
}
}
export interface Daemon {
readonly port: string | number;
}
export namespace Daemon {
export function is(
daemon: RecursivePartial<Daemon> | undefined
): daemon is Daemon {
return !!daemon && !!daemon.port;
}
export function sameAs(
left: RecursivePartial<Daemon> | undefined,
right: RecursivePartial<Daemon> | undefined
): boolean {
if (left === undefined) {
return right === undefined;
}
if (right === undefined) {
return left === undefined;
}
return String(left.port) === String(right.port);
}
}
export interface Directories {
readonly data: string;
readonly downloads: string;
@@ -123,6 +101,7 @@ export interface Network {
// Arduino CLI config scheme
export interface CliConfig {
locale?: string;
board_manager?: RecursivePartial<BoardManager>;
directories?: RecursivePartial<Directories>;
logging?: RecursivePartial<Logging>;

View File

@@ -95,6 +95,7 @@ export class ConfigServiceImpl
downloadsDirUri,
sketchDirUri,
network,
locale,
} = config;
copyDefaultCliConfig.directories = {
data: FileUri.fsPath(dataDirUri),
@@ -104,6 +105,7 @@ export class ConfigServiceImpl
copyDefaultCliConfig.board_manager = {
additional_urls: [...additionalUrls],
};
copyDefaultCliConfig.locale = locale || 'en';
const proxy = Network.stringify(network);
copyDefaultCliConfig.network = { proxy };
const { port } = copyDefaultCliConfig.daemon;
@@ -214,7 +216,7 @@ export class ConfigServiceImpl
protected async mapCliConfigToAppConfig(
cliConfig: DefaultCliConfig
): Promise<Config> {
const { directories } = cliConfig;
const { directories, locale = 'en', daemon } = cliConfig;
const { data, user, downloads } = directories;
const additionalUrls: Array<string> = [];
if (cliConfig.board_manager && cliConfig.board_manager.additional_urls) {
@@ -229,6 +231,8 @@ export class ConfigServiceImpl
downloadsDirUri: FileUri.create(downloads).toString(),
additionalUrls,
network,
locale,
daemon,
};
}

View File

@@ -1,214 +1,247 @@
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
const disableJSDOM = enableJSDOM();
// import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
// const disableJSDOM = enableJSDOM();
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
import { ApplicationProps } from '@theia/application-package/lib/application-props';
FrontendApplicationConfigProvider.set({
...ApplicationProps.DEFAULT.frontend.config,
});
// import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
// import { ApplicationProps } from '@theia/application-package/lib/application-props';
// FrontendApplicationConfigProvider.set({
// ...ApplicationProps.DEFAULT.frontend.config,
// });
import { MessageService } from '@theia/core';
import { BoardsServiceProvider } from '../../browser/boards/boards-service-provider';
import { BoardsListWidgetFrontendContribution } from '../../browser/boards/boards-widget-frontend-contribution';
import {
BoardsPackage,
BoardsService,
ResponseServiceArduino,
} from '../../common/protocol';
import { IMock, It, Mock, Times } from 'typemoq';
import { Container, ContainerModule } from 'inversify';
import { BoardsAutoInstaller } from '../../browser/boards/boards-auto-installer';
import { tick } from '../utils';
import { ListWidget } from '../../browser/widgets/component-list/list-widget';
import { aBoardConfig, anInstalledPackage, aPackage } from './fixtures/boards';
// import { MessageService } from '@theia/core';
// import { BoardsServiceProvider } from '../../browser/boards/boards-service-provider';
// import { BoardsListWidgetFrontendContribution } from '../../browser/boards/boards-widget-frontend-contribution';
// import {
// Board,
// BoardsPackage,
// BoardsService,
// Port,
// ResponseServiceArduino,
// } from '../../common/protocol';
// import { IMock, It, Mock, Times } from 'typemoq';
// import { Container, ContainerModule } from 'inversify';
// import { BoardsAutoInstaller } from '../../browser/boards/boards-auto-installer';
// import { BoardsConfig } from '../../browser/boards/boards-config';
// import { tick } from '../utils';
// import { ListWidget } from '../../browser/widgets/component-list/list-widget';
disableJSDOM();
// disableJSDOM();
describe('BoardsAutoInstaller', () => {
let subject: BoardsAutoInstaller;
let messageService: IMock<MessageService>;
let boardsService: IMock<BoardsService>;
let boardsServiceClient: IMock<BoardsServiceProvider>;
let responseService: IMock<ResponseServiceArduino>;
let boardsManagerFrontendContribution: IMock<BoardsListWidgetFrontendContribution>;
let boardsManagerWidget: IMock<ListWidget<BoardsPackage>>;
// const aBoard: Board = {
// fqbn: 'some:board:fqbn',
// name: 'Some Arduino Board',
// port: { address: '/lol/port1234', protocol: 'serial' },
// };
// const aPort: Port = {
// address: aBoard.port!.address,
// protocol: aBoard.port!.protocol,
// };
// const aBoardConfig: BoardsConfig.Config = {
// selectedBoard: aBoard,
// selectedPort: aPort,
// };
// const aPackage: BoardsPackage = {
// author: 'someAuthor',
// availableVersions: ['some.ver.sion', 'some.other.version'],
// boards: [aBoard],
// deprecated: false,
// description: 'Some Arduino Board, Some Other Arduino Board',
// id: 'some:arduinoCoreId',
// installable: true,
// moreInfoLink: 'http://www.some-url.lol/',
// name: 'Some Arduino Package',
// summary: 'Boards included in this package:',
// };
let testContainer: Container;
// const anInstalledPackage: BoardsPackage = {
// ...aPackage,
// installedVersion: 'some.ver.sion',
// };
beforeEach(() => {
testContainer = new Container();
messageService = Mock.ofType<MessageService>();
boardsService = Mock.ofType<BoardsService>();
boardsServiceClient = Mock.ofType<BoardsServiceProvider>();
responseService = Mock.ofType<ResponseServiceArduino>();
boardsManagerFrontendContribution =
Mock.ofType<BoardsListWidgetFrontendContribution>();
boardsManagerWidget = Mock.ofType<ListWidget<BoardsPackage>>();
// describe('BoardsAutoInstaller', () => {
// let subject: BoardsAutoInstaller;
// let messageService: IMock<MessageService>;
// let boardsService: IMock<BoardsService>;
// let boardsServiceClient: IMock<BoardsServiceProvider>;
// let responseService: IMock<ResponseServiceArduino>;
// let boardsManagerFrontendContribution: IMock<BoardsListWidgetFrontendContribution>;
// let boardsManagerWidget: IMock<ListWidget<BoardsPackage>>;
boardsManagerWidget.setup((b) =>
b.refresh(aPackage.name.toLocaleLowerCase())
);
// let testContainer: Container;
boardsManagerFrontendContribution
.setup((b) => b.openView({ reveal: true }))
.returns(async () => boardsManagerWidget.object);
// beforeEach(() => {
// testContainer = new Container();
// messageService = Mock.ofType<MessageService>();
// boardsService = Mock.ofType<BoardsService>();
// boardsServiceClient = Mock.ofType<BoardsServiceProvider>();
// responseService = Mock.ofType<ResponseServiceArduino>();
// boardsManagerFrontendContribution =
// Mock.ofType<BoardsListWidgetFrontendContribution>();
// boardsManagerWidget = Mock.ofType<ListWidget<BoardsPackage>>();
messageService
.setup((m) => m.showProgress(It.isAny(), It.isAny()))
.returns(async () => ({
cancel: () => null,
id: '',
report: () => null,
result: Promise.resolve(''),
}));
// boardsManagerWidget.setup((b) =>
// b.refresh(aPackage.name.toLocaleLowerCase())
// );
responseService
.setup((r) => r.onProgressDidChange(It.isAny()))
.returns(() => ({ dispose: () => null }));
// boardsManagerFrontendContribution
// .setup((b) => b.openView({ reveal: true }))
// .returns(async () => boardsManagerWidget.object);
const module = new ContainerModule((bind) => {
bind(BoardsAutoInstaller).toSelf();
bind(MessageService).toConstantValue(messageService.object);
bind(BoardsService).toConstantValue(boardsService.object);
bind(BoardsServiceProvider).toConstantValue(boardsServiceClient.object);
bind(ResponseServiceArduino).toConstantValue(responseService.object);
bind(BoardsListWidgetFrontendContribution).toConstantValue(
boardsManagerFrontendContribution.object
);
});
// messageService
// .setup((m) => m.showProgress(It.isAny(), It.isAny()))
// .returns(async () => ({
// cancel: () => null,
// id: '',
// report: () => null,
// result: Promise.resolve(''),
// }));
testContainer.load(module);
subject = testContainer.get(BoardsAutoInstaller);
});
// responseService
// .setup((r) => r.onProgressDidChange(It.isAny()))
// .returns(() => ({ dispose: () => null }));
context('when it starts', () => {
it('should register to the BoardsServiceClient in order to check the packages every a new board is plugged in', () => {
subject.onStart();
boardsServiceClient.verify(
(b) => b.onBoardsConfigChanged(It.isAny()),
Times.once()
);
});
// const module = new ContainerModule((bind) => {
// bind(BoardsAutoInstaller).toSelf();
// bind(MessageService).toConstantValue(messageService.object);
// bind(BoardsService).toConstantValue(boardsService.object);
// bind(BoardsServiceProvider).toConstantValue(boardsServiceClient.object);
// bind(ResponseServiceArduino).toConstantValue(responseService.object);
// bind(BoardsListWidgetFrontendContribution).toConstantValue(
// boardsManagerFrontendContribution.object
// );
// });
context('and it checks the installable packages', () => {
context(`and a port and a board a selected`, () => {
beforeEach(() => {
boardsServiceClient
.setup((b) => b.boardsConfig)
.returns(() => aBoardConfig);
});
context('if no package for the board is already installed', () => {
context('if a candidate package for the board is found', () => {
beforeEach(() => {
boardsService
.setup((b) => b.search(It.isValue({})))
.returns(async () => [aPackage]);
});
it('should show a notification suggesting to install that package', async () => {
messageService
.setup((m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
)
.returns(() => Promise.resolve('Install Manually'));
subject.onStart();
await tick();
messageService.verify(
(m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
Times.once()
);
});
context(`if the answer to the message is 'Yes'`, () => {
beforeEach(() => {
messageService
.setup((m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
)
.returns(() => Promise.resolve('Yes'));
});
it('should install the package', async () => {
subject.onStart();
// testContainer.load(module);
// subject = testContainer.get(BoardsAutoInstaller);
// });
await tick();
// context('when it starts', () => {
// it('should register to the BoardsServiceClient in order to check the packages every a new board is plugged in', () => {
// subject.onStart();
// boardsServiceClient.verify(
// (b) => b.onBoardsConfigChanged(It.isAny()),
// Times.once()
// );
// });
messageService.verify(
(m) => m.showProgress(It.isAny(), It.isAny()),
Times.once()
);
});
});
context(
`if the answer to the message is 'Install Manually'`,
() => {
beforeEach(() => {
messageService
.setup((m) =>
m.info(
It.isAnyString(),
It.isAnyString(),
It.isAnyString()
)
)
.returns(() => Promise.resolve('Install Manually'));
});
it('should open the boards manager widget', () => {
subject.onStart();
});
}
);
});
context('if a candidate package for the board is not found', () => {
beforeEach(() => {
boardsService
.setup((b) => b.search(It.isValue({})))
.returns(async () => []);
});
it('should do nothing', async () => {
subject.onStart();
await tick();
messageService.verify(
(m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
Times.never()
);
});
});
});
context(
'if one of the packages for the board is already installed',
() => {
beforeEach(() => {
boardsService
.setup((b) => b.search(It.isValue({})))
.returns(async () => [aPackage, anInstalledPackage]);
messageService
.setup((m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
)
.returns(() => Promise.resolve('Yes'));
});
it('should do nothing', async () => {
subject.onStart();
await tick();
messageService.verify(
(m) =>
m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
Times.never()
);
});
}
);
});
context('and there is no selected board or port', () => {
it('should do nothing', async () => {
subject.onStart();
await tick();
messageService.verify(
(m) => m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
Times.never()
);
});
});
});
});
});
// context('and it checks the installable packages', () => {
// context(`and a port and a board a selected`, () => {
// beforeEach(() => {
// boardsServiceClient
// .setup((b) => b.boardsConfig)
// .returns(() => aBoardConfig);
// });
// context('if no package for the board is already installed', () => {
// context('if a candidate package for the board is found', () => {
// beforeEach(() => {
// boardsService
// .setup((b) => b.search(It.isValue({})))
// .returns(async () => [aPackage]);
// });
// it('should show a notification suggesting to install that package', async () => {
// messageService
// .setup((m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
// )
// .returns(() => Promise.resolve('Install Manually'));
// subject.onStart();
// await tick();
// messageService.verify(
// (m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
// Times.once()
// );
// });
// context(`if the answer to the message is 'Yes'`, () => {
// beforeEach(() => {
// messageService
// .setup((m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
// )
// .returns(() => Promise.resolve('Yes'));
// });
// it('should install the package', async () => {
// subject.onStart();
// await tick();
// messageService.verify(
// (m) => m.showProgress(It.isAny(), It.isAny()),
// Times.once()
// );
// });
// });
// context(
// `if the answer to the message is 'Install Manually'`,
// () => {
// beforeEach(() => {
// messageService
// .setup((m) =>
// m.info(
// It.isAnyString(),
// It.isAnyString(),
// It.isAnyString()
// )
// )
// .returns(() => Promise.resolve('Install Manually'));
// });
// it('should open the boards manager widget', () => {
// subject.onStart();
// });
// }
// );
// });
// context('if a candidate package for the board is not found', () => {
// beforeEach(() => {
// boardsService
// .setup((b) => b.search(It.isValue({})))
// .returns(async () => []);
// });
// it('should do nothing', async () => {
// subject.onStart();
// await tick();
// messageService.verify(
// (m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
// Times.never()
// );
// });
// });
// });
// context(
// 'if one of the packages for the board is already installed',
// () => {
// beforeEach(() => {
// boardsService
// .setup((b) => b.search(It.isValue({})))
// .returns(async () => [aPackage, anInstalledPackage]);
// messageService
// .setup((m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString())
// )
// .returns(() => Promise.resolve('Yes'));
// });
// it('should do nothing', async () => {
// subject.onStart();
// await tick();
// messageService.verify(
// (m) =>
// m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
// Times.never()
// );
// });
// }
// );
// });
// context('and there is no selected board or port', () => {
// it('should do nothing', async () => {
// subject.onStart();
// await tick();
// messageService.verify(
// (m) => m.info(It.isAnyString(), It.isAnyString(), It.isAnyString()),
// Times.never()
// );
// });
// });
// });
// });
// });