mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-09-30 15:18:32 +00:00
Compare commits
32 Commits
2.0.0-rc9
...
2.0.0-rc9.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9cabd40429 | ||
![]() |
6e3681896c | ||
![]() |
8a1cabd2bc | ||
![]() |
7a3e6789d1 | ||
![]() |
92bc5ecf7b | ||
![]() |
aebec0f942 | ||
![]() |
54db9bbce8 | ||
![]() |
676eb2f588 | ||
![]() |
ce273adf77 | ||
![]() |
0b33b51700 | ||
![]() |
36ac47b975 | ||
![]() |
bf193b1cac | ||
![]() |
879aedeaa3 | ||
![]() |
d556ee95c0 | ||
![]() |
d93c9ba654 | ||
![]() |
8a0dc1be7e | ||
![]() |
564862e173 | ||
![]() |
d7f7010bb5 | ||
![]() |
e156dcc213 | ||
![]() |
27a2a6ca03 | ||
![]() |
581379f86f | ||
![]() |
b62f3dec84 | ||
![]() |
90d2950bdd | ||
![]() |
5b7d64c1c1 | ||
![]() |
55927ac3dd | ||
![]() |
40c93bc19a | ||
![]() |
59b8a2d6bb | ||
![]() |
124738d810 | ||
![]() |
19c0334a91 | ||
![]() |
f22be3c587 | ||
![]() |
9373a0bcaf | ||
![]() |
5087ff08f2 |
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
@@ -20,7 +20,6 @@
|
||||
"--no-app-auto-install",
|
||||
"--plugins=local-dir:../plugins",
|
||||
"--hosted-plugin-inspect=9339",
|
||||
"--nosplash",
|
||||
"--content-trace",
|
||||
"--open-devtools"
|
||||
],
|
||||
|
@@ -41,7 +41,7 @@ The _frontend_ is running as an Electron renderer process and can invoke service
|
||||
|
||||
If you’re familiar with TypeScript, the [Theia IDE](https://theia-ide.org/), and if you want to contribute to the
|
||||
project, you should be able to build the Arduino IDE locally.
|
||||
Please refer to the [Theia IDE prerequisites](https://github.com/theia-ide/theia/blob/master/doc/) documentation for the setup instructions.
|
||||
Please refer to the [Theia IDE prerequisites](https://github.com/eclipse-theia/theia/blob/master/doc/Developing.md#prerequisites) documentation for the setup instructions.
|
||||
> **Note**: Node.js 14 must be used instead of the version 12 recommended at the link above.
|
||||
|
||||
Once you have all the tools installed, you can build the editor following these steps
|
||||
@@ -89,7 +89,6 @@ This project is built on [GitHub Actions](https://github.com/arduino/arduino-ide
|
||||
git push origin 1.2.3
|
||||
```
|
||||
|
||||
|
||||
## Notes for macOS contributors
|
||||
Beginning in macOS 10.14.5, the software [must be notarized to run](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution). The signing and notarization processes for the Arduino IDE are managed by our Continuous Integration (CI) workflows, implemented with GitHub Actions. On every push and pull request, the Arduino IDE is built and saved to a workflow artifact. These artifacts can be used by contributors and beta testers who don't want to set up a build system locally.
|
||||
For security reasons, signing and notarization are disabled for workflow runs for pull requests from forks of this repository. This means that macOS will block you from running those artifacts.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "arduino-ide-extension",
|
||||
"version": "2.0.0-rc9",
|
||||
"version": "2.0.0-rc9.2",
|
||||
"description": "An extension for Theia building the Arduino IDE",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
@@ -150,13 +150,17 @@
|
||||
"frontend": "lib/browser/theia/core/browser-menu-module",
|
||||
"frontendElectron": "lib/electron-browser/theia/core/electron-menu-module"
|
||||
},
|
||||
{
|
||||
"frontend": "lib/browser/theia/core/browser-window-module",
|
||||
"frontendElectron": "lib/electron-browser/theia/core/electron-window-module"
|
||||
},
|
||||
{
|
||||
"electronMain": "lib/electron-main/arduino-electron-main-module"
|
||||
}
|
||||
],
|
||||
"arduino": {
|
||||
"cli": {
|
||||
"version": "0.25.0"
|
||||
"version": "0.26.0-rc.1"
|
||||
},
|
||||
"fwuploader": {
|
||||
"version": "2.2.0"
|
||||
|
@@ -104,7 +104,7 @@ export class ArduinoFrontendContribution
|
||||
}
|
||||
}
|
||||
});
|
||||
this.appStateService.reachedState('initialized_layout').then(() =>
|
||||
this.appStateService.reachedState('ready').then(() =>
|
||||
this.arduinoPreferences.ready.then(() => {
|
||||
const webContents = remote.getCurrentWebContents();
|
||||
const zoomLevel = this.arduinoPreferences.get(
|
||||
@@ -183,34 +183,6 @@ export class ArduinoFrontendContribution
|
||||
|
||||
registerColors(colors: ColorRegistry): void {
|
||||
colors.register(
|
||||
{
|
||||
id: 'arduino.branding.primary',
|
||||
defaults: {
|
||||
dark: 'statusBar.background',
|
||||
light: 'statusBar.background',
|
||||
},
|
||||
description:
|
||||
'The primary branding color, such as dialog titles, library, and board manager list labels.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.branding.secondary',
|
||||
defaults: {
|
||||
dark: 'statusBar.background',
|
||||
light: 'statusBar.background',
|
||||
},
|
||||
description:
|
||||
'Secondary branding color for list selections, dropdowns, and widget borders.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.foreground',
|
||||
defaults: {
|
||||
dark: 'editorWidget.background',
|
||||
light: 'editorWidget.background',
|
||||
hc: 'editorWidget.background',
|
||||
},
|
||||
description:
|
||||
'Color of the Arduino IDE foreground which is used for dialogs, such as the Select Board dialog.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.toolbar.button.background',
|
||||
defaults: {
|
||||
@@ -225,8 +197,8 @@ export class ArduinoFrontendContribution
|
||||
id: 'arduino.toolbar.button.hoverBackground',
|
||||
defaults: {
|
||||
dark: 'button.hoverBackground',
|
||||
light: 'button.foreground',
|
||||
hc: 'textLink.foreground',
|
||||
light: 'button.hoverBackground',
|
||||
hc: 'button.background',
|
||||
},
|
||||
description:
|
||||
'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.',
|
||||
@@ -261,24 +233,6 @@ export class ArduinoFrontendContribution
|
||||
description:
|
||||
'Toggle color of the toolbar items when they are currently toggled (the command is in progress)',
|
||||
},
|
||||
{
|
||||
id: 'arduino.output.foreground',
|
||||
defaults: {
|
||||
dark: 'editor.foreground',
|
||||
light: 'editor.foreground',
|
||||
hc: 'editor.foreground',
|
||||
},
|
||||
description: 'Color of the text in the Output view.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.output.background',
|
||||
defaults: {
|
||||
dark: 'editor.background',
|
||||
light: 'editor.background',
|
||||
hc: 'editor.background',
|
||||
},
|
||||
description: 'Background color of the Output view.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.toolbar.dropdown.border',
|
||||
defaults: {
|
||||
@@ -303,8 +257,8 @@ export class ArduinoFrontendContribution
|
||||
id: 'arduino.toolbar.dropdown.background',
|
||||
defaults: {
|
||||
dark: 'tab.unfocusedActiveBackground',
|
||||
light: 'tab.unfocusedActiveBackground',
|
||||
hc: 'tab.unfocusedActiveBackground',
|
||||
light: 'dropdown.background',
|
||||
hc: 'dropdown.background',
|
||||
},
|
||||
description: 'Background color of the Board Selector.',
|
||||
},
|
||||
@@ -312,18 +266,18 @@ export class ArduinoFrontendContribution
|
||||
{
|
||||
id: 'arduino.toolbar.dropdown.label',
|
||||
defaults: {
|
||||
dark: 'foreground',
|
||||
light: 'foreground',
|
||||
hc: 'foreground',
|
||||
dark: 'dropdown.foreground',
|
||||
light: 'dropdown.foreground',
|
||||
hc: 'dropdown.foreground',
|
||||
},
|
||||
description: 'Font color of the Board Selector.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.toolbar.dropdown.iconSelected',
|
||||
defaults: {
|
||||
dark: 'statusBar.background',
|
||||
light: 'statusBar.background',
|
||||
hc: 'statusBar.background',
|
||||
dark: 'list.activeSelectionIconForeground',
|
||||
light: 'list.activeSelectionIconForeground',
|
||||
hc: 'list.activeSelectionIconForeground',
|
||||
},
|
||||
description:
|
||||
'Color of the selected protocol icon in the Board Selector.',
|
||||
@@ -331,18 +285,18 @@ export class ArduinoFrontendContribution
|
||||
{
|
||||
id: 'arduino.toolbar.dropdown.option.backgroundHover',
|
||||
defaults: {
|
||||
dark: 'editor.background',
|
||||
light: 'editor.background',
|
||||
hc: 'editor.background',
|
||||
dark: 'list.hoverBackground',
|
||||
light: 'list.hoverBackground',
|
||||
hc: 'list.hoverBackground',
|
||||
},
|
||||
description: 'Background color on hover of the Board Selector options.',
|
||||
},
|
||||
{
|
||||
id: 'arduino.toolbar.dropdown.option.backgroundSelected',
|
||||
defaults: {
|
||||
dark: 'editor.background',
|
||||
light: 'editor.background',
|
||||
hc: 'editor.background',
|
||||
dark: 'list.activeSelectionBackground',
|
||||
light: 'list.activeSelectionBackground',
|
||||
hc: 'list.activeSelectionBackground',
|
||||
},
|
||||
description:
|
||||
'Background color of the selected board in the Board Selector.',
|
||||
|
@@ -50,13 +50,17 @@ import {
|
||||
ApplicationShell as TheiaApplicationShell,
|
||||
ShellLayoutRestorer as TheiaShellLayoutRestorer,
|
||||
CommonFrontendContribution as TheiaCommonFrontendContribution,
|
||||
DockPanelRenderer as TheiaDockPanelRenderer,
|
||||
TabBarRendererFactory,
|
||||
ContextMenuRenderer,
|
||||
createTreeContainer,
|
||||
TreeWidget,
|
||||
} from '@theia/core/lib/browser';
|
||||
import { MenuContribution } from '@theia/core/lib/common/menu';
|
||||
import { ApplicationShell } from './theia/core/application-shell';
|
||||
import {
|
||||
ApplicationShell,
|
||||
DockPanelRenderer,
|
||||
} from './theia/core/application-shell';
|
||||
import { FrontendApplication } from './theia/core/frontend-application';
|
||||
import {
|
||||
BoardsConfigDialog,
|
||||
@@ -82,7 +86,10 @@ import { BoardsAutoInstaller } from './boards/boards-auto-installer';
|
||||
import { ShellLayoutRestorer } from './theia/core/shell-layout-restorer';
|
||||
import { ListItemRenderer } from './widgets/component-list/list-item-renderer';
|
||||
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
|
||||
import { MonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
|
||||
import {
|
||||
MonacoThemeJson,
|
||||
MonacoThemingService,
|
||||
} from '@theia/monaco/lib/browser/monaco-theming-service';
|
||||
import {
|
||||
ArduinoDaemonPath,
|
||||
ArduinoDaemon,
|
||||
@@ -310,20 +317,36 @@ import { SelectedBoard } from './contributions/selected-board';
|
||||
import { CheckForUpdates } from './contributions/check-for-updates';
|
||||
import { OpenBoardsConfig } from './contributions/open-boards-config';
|
||||
import { SketchFilesTracker } from './contributions/sketch-files-tracker';
|
||||
import { MonacoThemeServiceIsReady } from './utils/window';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { StatusBarImpl } from './theia/core/status-bar';
|
||||
import { StatusBarImpl as TheiaStatusBarImpl } from '@theia/core/lib/browser';
|
||||
|
||||
MonacoThemingService.register({
|
||||
id: 'arduino-theme',
|
||||
label: 'Light (Arduino)',
|
||||
uiTheme: 'vs',
|
||||
json: require('../../src/browser/data/default.color-theme.json'),
|
||||
});
|
||||
|
||||
MonacoThemingService.register({
|
||||
id: 'arduino-theme-dark',
|
||||
label: 'Dark (Arduino)',
|
||||
uiTheme: 'vs-dark',
|
||||
json: require('../../src/browser/data/dark.color-theme.json'),
|
||||
});
|
||||
const registerArduinoThemes = () => {
|
||||
const themes: MonacoThemeJson[] = [
|
||||
{
|
||||
id: 'arduino-theme',
|
||||
label: 'Light (Arduino)',
|
||||
uiTheme: 'vs',
|
||||
json: require('../../src/browser/data/default.color-theme.json'),
|
||||
},
|
||||
{
|
||||
id: 'arduino-theme-dark',
|
||||
label: 'Dark (Arduino)',
|
||||
uiTheme: 'vs-dark',
|
||||
json: require('../../src/browser/data/dark.color-theme.json'),
|
||||
},
|
||||
];
|
||||
themes.forEach((theme) => MonacoThemingService.register(theme));
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const global = window as any;
|
||||
const ready = global[MonacoThemeServiceIsReady] as Deferred;
|
||||
if (ready) {
|
||||
ready.promise.then(registerArduinoThemes);
|
||||
} else {
|
||||
registerArduinoThemes();
|
||||
}
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
// Commands and toolbar items
|
||||
@@ -566,7 +589,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
|
||||
// Disabled reference counter in the editor manager to avoid opening the same editor (with different opener options) multiple times.
|
||||
bind(EditorManager).toSelf().inSingletonScope();
|
||||
rebind(TheiaEditorManager).to(EditorManager);
|
||||
rebind(TheiaEditorManager).toService(EditorManager);
|
||||
|
||||
// replace search icon
|
||||
rebind(TheiaSearchInWorkspaceFactory)
|
||||
@@ -805,6 +828,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(WidgetManager).toSelf().inSingletonScope();
|
||||
rebind(TheiaWidgetManager).toService(WidgetManager);
|
||||
|
||||
// To avoid running a status bar update on every single `keypress` event from the editor.
|
||||
bind(StatusBarImpl).toSelf().inSingletonScope();
|
||||
rebind(TheiaStatusBarImpl).toService(StatusBarImpl);
|
||||
|
||||
// Debounced update for the tab-bar toolbar when typing in the editor.
|
||||
bind(DockPanelRenderer).toSelf();
|
||||
rebind(TheiaDockPanelRenderer).toService(DockPanelRenderer);
|
||||
|
||||
// Preferences
|
||||
bindArduinoPreferences(bind);
|
||||
|
||||
|
@@ -237,6 +237,16 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
);
|
||||
|
||||
const actions: AutoInstallPromptActions = [
|
||||
{
|
||||
key: manualInstall,
|
||||
handler: () => {
|
||||
this.boardsManagerFrontendContribution
|
||||
.openView({ reveal: true })
|
||||
.then((widget) =>
|
||||
widget.refresh(candidate.name.toLocaleLowerCase())
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
isAcceptance: true,
|
||||
key: yes,
|
||||
@@ -250,16 +260,6 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
key: manualInstall,
|
||||
handler: () => {
|
||||
this.boardsManagerFrontendContribution
|
||||
.openView({ reveal: true })
|
||||
.then((widget) =>
|
||||
widget.refresh(candidate.name.toLocaleLowerCase())
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return actions;
|
||||
|
@@ -130,11 +130,14 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
|
||||
protocolIcon
|
||||
)}
|
||||
/>
|
||||
<div className="arduino-boards-dropdown-item--label">
|
||||
<div className="arduino-boards-dropdown-item--board-label">
|
||||
<div
|
||||
className="arduino-boards-dropdown-item--label"
|
||||
title={`${boardLabel}\n${port.address}`}
|
||||
>
|
||||
<div className="arduino-boards-dropdown-item--board-label noWrapInfo noselect">
|
||||
{boardLabel}
|
||||
</div>
|
||||
<div className="arduino-boards-dropdown-item--port-label">
|
||||
<div className="arduino-boards-dropdown-item--port-label noWrapInfo noselect">
|
||||
{port.address}
|
||||
</div>
|
||||
</div>
|
||||
@@ -229,7 +232,8 @@ export class BoardsToolBarItem extends React.Component<
|
||||
<div
|
||||
className={classNames(
|
||||
'arduino-boards-toolbar-item--label',
|
||||
'noWrapInfo noselect',
|
||||
'noWrapInfo',
|
||||
'noselect',
|
||||
{ 'arduino-boards-toolbar-item--label-connected': isConnected }
|
||||
)}
|
||||
>
|
||||
|
@@ -4,11 +4,8 @@ import URI from '@theia/core/lib/common/uri';
|
||||
import { ConfirmDialog } from '@theia/core/lib/browser/dialogs';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import {
|
||||
Installable,
|
||||
LibraryService,
|
||||
ResponseServiceClient,
|
||||
} from '../../common/protocol';
|
||||
import { LibraryService, ResponseServiceClient } from '../../common/protocol';
|
||||
import { ExecuteWithProgress } from '../../common/protocol/progressible';
|
||||
import {
|
||||
SketchContribution,
|
||||
Command,
|
||||
@@ -88,7 +85,7 @@ export class AddZipLibrary extends SketchContribution {
|
||||
|
||||
private async doInstall(zipUri: string, overwrite?: boolean): Promise<void> {
|
||||
try {
|
||||
await Installable.doWithProgress({
|
||||
await ExecuteWithProgress.doWithProgress({
|
||||
messageService: this.messageService,
|
||||
progressText:
|
||||
nls.localize('arduino/common/processing', 'Processing') +
|
||||
|
@@ -1,23 +1,16 @@
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import {
|
||||
CoreServiceContribution,
|
||||
Command,
|
||||
CommandRegistry,
|
||||
CoreServiceContribution,
|
||||
MenuModelRegistry,
|
||||
} from './contribution';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
|
||||
@injectable()
|
||||
export class BurnBootloader extends CoreServiceContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
override registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(BurnBootloader.Commands.BURN_BOOTLOADER, {
|
||||
execute: () => this.burnBootloader(),
|
||||
@@ -35,32 +28,19 @@ export class BurnBootloader extends CoreServiceContribution {
|
||||
});
|
||||
}
|
||||
|
||||
async burnBootloader(): Promise<void> {
|
||||
private async burnBootloader(): Promise<void> {
|
||||
const options = await this.options();
|
||||
try {
|
||||
const { boardsConfig } = this.boardsServiceClientImpl;
|
||||
const port = boardsConfig.selectedPort;
|
||||
const [fqbn, { selectedProgrammer: programmer }, verify, verbose] =
|
||||
await Promise.all([
|
||||
this.boardsDataStore.appendConfigToFqbn(
|
||||
boardsConfig.selectedBoard?.fqbn
|
||||
),
|
||||
this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn),
|
||||
this.preferences.get('arduino.upload.verify'),
|
||||
this.preferences.get('arduino.upload.verbose'),
|
||||
]);
|
||||
|
||||
const board = {
|
||||
...boardsConfig.selectedBoard,
|
||||
name: boardsConfig.selectedBoard?.name || '',
|
||||
fqbn,
|
||||
};
|
||||
this.outputChannelManager.getChannel('Arduino').clear();
|
||||
await this.coreService.burnBootloader({
|
||||
board,
|
||||
programmer,
|
||||
port,
|
||||
verify,
|
||||
verbose,
|
||||
await this.doWithProgress({
|
||||
progressText: nls.localize(
|
||||
'arduino/bootloader/burningBootloader',
|
||||
'Burning bootloader...'
|
||||
),
|
||||
task: (progressId, coreService) =>
|
||||
coreService.burnBootloader({
|
||||
...options,
|
||||
progressId,
|
||||
}),
|
||||
});
|
||||
this.messageService.info(
|
||||
nls.localize(
|
||||
@@ -75,6 +55,27 @@ export class BurnBootloader extends CoreServiceContribution {
|
||||
this.handleError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async options(): Promise<CoreService.Options.Bootloader> {
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
const port = boardsConfig.selectedPort;
|
||||
const [fqbn, { selectedProgrammer: programmer }, verify, verbose] =
|
||||
await Promise.all([
|
||||
this.boardsDataStore.appendConfigToFqbn(
|
||||
boardsConfig.selectedBoard?.fqbn
|
||||
),
|
||||
this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn),
|
||||
this.preferences.get('arduino.upload.verify'),
|
||||
this.preferences.get('arduino.upload.verbose'),
|
||||
]);
|
||||
return {
|
||||
fqbn,
|
||||
programmer,
|
||||
port,
|
||||
verify,
|
||||
verbose,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace BurnBootloader {
|
||||
|
@@ -49,13 +49,16 @@ import {
|
||||
Sketch,
|
||||
CoreService,
|
||||
CoreError,
|
||||
ResponseServiceClient,
|
||||
} from '../../common/protocol';
|
||||
import { ArduinoPreferences } from '../arduino-preferences';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { CoreErrorHandler } from './core-error-handler';
|
||||
import { nls } from '@theia/core';
|
||||
import { OutputChannelManager } from '../theia/output/output-channel';
|
||||
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
|
||||
import { ExecuteWithProgress } from '../../common/protocol/progressible';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
|
||||
export {
|
||||
Command,
|
||||
@@ -167,18 +170,23 @@ export abstract class SketchContribution extends Contribution {
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceContribution extends SketchContribution {
|
||||
@inject(CoreService)
|
||||
protected readonly coreService: CoreService;
|
||||
export abstract class CoreServiceContribution extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(CoreErrorHandler)
|
||||
protected readonly coreErrorHandler: CoreErrorHandler;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(CoreService)
|
||||
private readonly coreService: CoreService;
|
||||
|
||||
@inject(ClipboardService)
|
||||
private readonly clipboardService: ClipboardService;
|
||||
|
||||
@inject(ResponseServiceClient)
|
||||
private readonly responseService: ResponseServiceClient;
|
||||
|
||||
protected handleError(error: unknown): void {
|
||||
this.coreErrorHandler.tryHandle(error);
|
||||
this.tryToastErrorMessage(error);
|
||||
}
|
||||
|
||||
@@ -214,6 +222,25 @@ export class CoreServiceContribution extends SketchContribution {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
protected async doWithProgress<T>(options: {
|
||||
progressText: string;
|
||||
keepOutput?: boolean;
|
||||
task: (progressId: string, coreService: CoreService) => Promise<T>;
|
||||
}): Promise<T> {
|
||||
const { progressText, keepOutput, task } = options;
|
||||
this.outputChannelManager
|
||||
.getChannel('Arduino')
|
||||
.show({ preserveFocus: true });
|
||||
const result = await ExecuteWithProgress.doWithProgress({
|
||||
messageService: this.messageService,
|
||||
responseService: this.responseService,
|
||||
progressText,
|
||||
run: ({ progressId }) => task(progressId, this.coreService),
|
||||
keepOutput,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Contribution {
|
||||
|
@@ -141,6 +141,11 @@ ${value}
|
||||
label: nls.localize('arduino/editor/decreaseIndent', 'Decrease Indent'),
|
||||
order: '2',
|
||||
});
|
||||
registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, {
|
||||
commandId: EditContributions.Commands.AUTO_FORMAT.id,
|
||||
label: nls.localize('arduino/editor/autoFormat', 'Auto Format'),
|
||||
order: '3',
|
||||
});
|
||||
|
||||
registry.registerMenuAction(ArduinoMenus.EDIT__FONT_CONTROL_GROUP, {
|
||||
commandId: EditContributions.Commands.INCREASE_FONT_SIZE.id,
|
||||
@@ -248,10 +253,13 @@ ${value}
|
||||
});
|
||||
}
|
||||
|
||||
protected async current(): Promise<ICodeEditor | StandaloneCodeEditor | undefined> {
|
||||
protected async current(): Promise<
|
||||
ICodeEditor | StandaloneCodeEditor | undefined
|
||||
> {
|
||||
return (
|
||||
this.codeEditorService.getFocusedCodeEditor() ||
|
||||
this.codeEditorService.getActiveCodeEditor() || undefined
|
||||
this.codeEditorService.getActiveCodeEditor() ||
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -43,7 +43,7 @@ export class FirstStartupInstaller extends Contribution {
|
||||
// If arduino:avr installation fails because it's already installed we don't want to retry on next start-up
|
||||
console.error(e);
|
||||
} else {
|
||||
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
|
||||
// But if there is any other error (e.g.: no Internet connection), we want to retry next time
|
||||
avrPackageError = e;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export class FirstStartupInstaller extends Contribution {
|
||||
// If Arduino_BuiltIn installation fails because it's already installed we don't want to retry on next start-up
|
||||
console.log('error installing core', e);
|
||||
} else {
|
||||
// But if there is any other error (e.g.: no interntet cconnection), we want to retry next time
|
||||
// But if there is any other error (e.g.: no Internet connection), we want to retry next time
|
||||
builtInLibraryError = e;
|
||||
}
|
||||
}
|
||||
|
@@ -145,6 +145,7 @@ export class InoLanguage extends SketchContribution {
|
||||
name: name ? `"${name}"` : undefined,
|
||||
},
|
||||
realTimeDiagnostics,
|
||||
silentOutput: true,
|
||||
}
|
||||
),
|
||||
]);
|
||||
|
@@ -77,15 +77,11 @@ export class SaveAsSketch extends SketchContribution {
|
||||
const exists = await this.fileService.exists(
|
||||
sketchDirUri.resolve(sketch.name)
|
||||
);
|
||||
const defaultUri = exists
|
||||
? sketchDirUri.resolve(
|
||||
sketchDirUri
|
||||
.resolve(
|
||||
`${sketch.name}_copy_${dateFormat(new Date(), 'yyyymmddHHMMss')}`
|
||||
)
|
||||
.toString()
|
||||
)
|
||||
: sketchDirUri.resolve(sketch.name);
|
||||
const defaultUri = sketchDirUri.resolve(
|
||||
exists
|
||||
? `${sketch.name}_copy_${dateFormat(new Date(), 'yyyymmddHHMMss')}`
|
||||
: sketch.name
|
||||
);
|
||||
const defaultPath = await this.fileService.fsPath(defaultUri);
|
||||
const { filePath, canceled } = await remote.dialog.showSaveDialog({
|
||||
title: nls.localize(
|
||||
|
@@ -3,56 +3,47 @@ import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { BoardUserField, CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import {
|
||||
CoreServiceContribution,
|
||||
Command,
|
||||
CommandRegistry,
|
||||
MenuModelRegistry,
|
||||
KeybindingRegistry,
|
||||
TabBarToolbarRegistry,
|
||||
CoreServiceContribution,
|
||||
} from './contribution';
|
||||
import { UserFieldsDialog } from '../dialogs/user-fields/user-fields-dialog';
|
||||
import { DisposableCollection, nls } from '@theia/core/lib/common';
|
||||
import { CurrentSketch } from '../../common/protocol/sketches-service-client-impl';
|
||||
import type { VerifySketchParams } from './verify-sketch';
|
||||
|
||||
@injectable()
|
||||
export class UploadSketch extends CoreServiceContribution {
|
||||
@inject(MenuModelRegistry)
|
||||
protected readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
private readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(UserFieldsDialog)
|
||||
protected readonly userFieldsDialog: UserFieldsDialog;
|
||||
private readonly userFieldsDialog: UserFieldsDialog;
|
||||
|
||||
protected cachedUserFields: Map<string, BoardUserField[]> = new Map();
|
||||
private boardRequiresUserFields = false;
|
||||
private readonly cachedUserFields: Map<string, BoardUserField[]> = new Map();
|
||||
private readonly menuActionsDisposables = new DisposableCollection();
|
||||
|
||||
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
|
||||
readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
|
||||
protected uploadInProgress = false;
|
||||
protected boardRequiresUserFields = false;
|
||||
|
||||
protected readonly menuActionsDisposables = new DisposableCollection();
|
||||
private readonly onDidChangeEmitter = new Emitter<void>();
|
||||
private readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
private uploadInProgress = false;
|
||||
|
||||
protected override init(): void {
|
||||
super.init();
|
||||
this.boardsServiceClientImpl.onBoardsConfigChanged(async () => {
|
||||
this.boardsServiceProvider.onBoardsConfigChanged(async () => {
|
||||
const userFields =
|
||||
await this.boardsServiceClientImpl.selectedBoardUserFields();
|
||||
await this.boardsServiceProvider.selectedBoardUserFields();
|
||||
this.boardRequiresUserFields = userFields.length > 0;
|
||||
this.registerMenus(this.menuRegistry);
|
||||
});
|
||||
}
|
||||
|
||||
private selectedFqbnAddress(): string {
|
||||
const { boardsConfig } = this.boardsServiceClientImpl;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
const fqbn = boardsConfig.selectedBoard?.fqbn;
|
||||
if (!fqbn) {
|
||||
return '';
|
||||
@@ -76,7 +67,7 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
if (this.boardRequiresUserFields && !this.cachedUserFields.has(key)) {
|
||||
// Deep clone the array of board fields to avoid editing the cached ones
|
||||
this.userFieldsDialog.value = (
|
||||
await this.boardsServiceClientImpl.selectedBoardUserFields()
|
||||
await this.boardsServiceProvider.selectedBoardUserFields()
|
||||
).map((f) => ({ ...f }));
|
||||
const result = await this.userFieldsDialog.open();
|
||||
if (!result) {
|
||||
@@ -98,8 +89,7 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
const cached = this.cachedUserFields.get(key);
|
||||
// Deep clone the array of board fields to avoid editing the cached ones
|
||||
this.userFieldsDialog.value = (
|
||||
cached ??
|
||||
(await this.boardsServiceClientImpl.selectedBoardUserFields())
|
||||
cached ?? (await this.boardsServiceProvider.selectedBoardUserFields())
|
||||
).map((f) => ({ ...f }));
|
||||
|
||||
const result = await this.userFieldsDialog.open();
|
||||
@@ -130,7 +120,6 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
|
||||
override registerMenus(registry: MenuModelRegistry): void {
|
||||
this.menuActionsDisposables.dispose();
|
||||
|
||||
this.menuActionsDisposables.push(
|
||||
registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, {
|
||||
commandId: UploadSketch.Commands.UPLOAD_SKETCH.id,
|
||||
@@ -153,7 +142,7 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
new PlaceholderMenuNode(
|
||||
ArduinoMenus.SKETCH__MAIN_GROUP,
|
||||
// commandId: UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION.id,
|
||||
UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION.label!,
|
||||
UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION.label,
|
||||
{ order: '2' }
|
||||
)
|
||||
)
|
||||
@@ -193,54 +182,42 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
}
|
||||
|
||||
async uploadSketch(usingProgrammer = false): Promise<void> {
|
||||
// even with buttons disabled, better to double check if an upload is already in progress
|
||||
if (this.uploadInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!CurrentSketch.isValid(sketch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// toggle the toolbar button and menu item state.
|
||||
// uploadInProgress will be set to false whether the upload fails or not
|
||||
this.uploadInProgress = true;
|
||||
this.coreErrorHandler.reset();
|
||||
this.onDidChangeEmitter.fire();
|
||||
const { boardsConfig } = this.boardsServiceClientImpl;
|
||||
const [
|
||||
fqbn,
|
||||
{ selectedProgrammer },
|
||||
verify,
|
||||
verbose,
|
||||
sourceOverride,
|
||||
optimizeForDebug,
|
||||
] = await Promise.all([
|
||||
this.boardsDataStore.appendConfigToFqbn(
|
||||
boardsConfig.selectedBoard?.fqbn
|
||||
),
|
||||
this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn),
|
||||
this.preferences.get('arduino.upload.verify'),
|
||||
this.preferences.get('arduino.upload.verbose'),
|
||||
this.sourceOverride(),
|
||||
this.commandService.executeCommand<boolean>(
|
||||
'arduino-is-optimize-for-debug'
|
||||
),
|
||||
]);
|
||||
|
||||
const board = {
|
||||
...boardsConfig.selectedBoard,
|
||||
name: boardsConfig.selectedBoard?.name || '',
|
||||
fqbn,
|
||||
};
|
||||
let options: CoreService.Upload.Options | undefined = undefined;
|
||||
const { selectedPort } = boardsConfig;
|
||||
const port = selectedPort;
|
||||
const userFields =
|
||||
this.cachedUserFields.get(this.selectedFqbnAddress()) ?? [];
|
||||
if (userFields.length === 0 && this.boardRequiresUserFields) {
|
||||
const verifyOptions =
|
||||
await this.commandService.executeCommand<CoreService.Options.Compile>(
|
||||
'arduino-verify-sketch',
|
||||
<VerifySketchParams>{
|
||||
exportBinaries: false,
|
||||
silent: true,
|
||||
}
|
||||
);
|
||||
if (!verifyOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadOptions = await this.uploadOptions(
|
||||
usingProgrammer,
|
||||
verifyOptions
|
||||
);
|
||||
if (!uploadOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: This does not belong here.
|
||||
// IDE2 should not do any preliminary checks but let the CLI fail and then toast a user consumable error message.
|
||||
if (
|
||||
uploadOptions.userFields.length === 0 &&
|
||||
this.boardRequiresUserFields
|
||||
) {
|
||||
this.messageService.error(
|
||||
nls.localize(
|
||||
'arduino/sketch/userFieldsNotFoundError',
|
||||
@@ -250,37 +227,13 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usingProgrammer) {
|
||||
const programmer = selectedProgrammer;
|
||||
options = {
|
||||
sketch,
|
||||
board,
|
||||
optimizeForDebug: Boolean(optimizeForDebug),
|
||||
programmer,
|
||||
port,
|
||||
verbose,
|
||||
verify,
|
||||
sourceOverride,
|
||||
userFields,
|
||||
};
|
||||
} else {
|
||||
options = {
|
||||
sketch,
|
||||
board,
|
||||
optimizeForDebug: Boolean(optimizeForDebug),
|
||||
port,
|
||||
verbose,
|
||||
verify,
|
||||
sourceOverride,
|
||||
userFields,
|
||||
};
|
||||
}
|
||||
this.outputChannelManager.getChannel('Arduino').clear();
|
||||
if (usingProgrammer) {
|
||||
await this.coreService.uploadUsingProgrammer(options);
|
||||
} else {
|
||||
await this.coreService.upload(options);
|
||||
}
|
||||
await this.doWithProgress({
|
||||
progressText: nls.localize('arduino/sketch/uploading', 'Uploading...'),
|
||||
task: (progressId, coreService) =>
|
||||
coreService.upload({ ...uploadOptions, progressId }),
|
||||
keepOutput: true,
|
||||
});
|
||||
|
||||
this.messageService.info(
|
||||
nls.localize('arduino/sketch/doneUploading', 'Done uploading.'),
|
||||
{ timeout: 3000 }
|
||||
@@ -292,6 +245,52 @@ export class UploadSketch extends CoreServiceContribution {
|
||||
this.onDidChangeEmitter.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private async uploadOptions(
|
||||
usingProgrammer: boolean,
|
||||
verifyOptions: CoreService.Options.Compile
|
||||
): Promise<CoreService.Options.Upload | undefined> {
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!CurrentSketch.isValid(sketch)) {
|
||||
return undefined;
|
||||
}
|
||||
const userFields = this.userFields();
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
const [fqbn, { selectedProgrammer: programmer }, verify, verbose] =
|
||||
await Promise.all([
|
||||
verifyOptions.fqbn, // already decorated FQBN
|
||||
this.boardsDataStore.getData(this.sanitizeFqbn(verifyOptions.fqbn)),
|
||||
this.preferences.get('arduino.upload.verify'),
|
||||
this.preferences.get('arduino.upload.verbose'),
|
||||
]);
|
||||
const port = boardsConfig.selectedPort;
|
||||
return {
|
||||
sketch,
|
||||
fqbn,
|
||||
...(usingProgrammer && { programmer }),
|
||||
port,
|
||||
verbose,
|
||||
verify,
|
||||
userFields,
|
||||
};
|
||||
}
|
||||
|
||||
private userFields() {
|
||||
return this.cachedUserFields.get(this.selectedFqbnAddress()) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the `VENDOR:ARCHITECTURE:BOARD_ID[:MENU_ID=OPTION_ID[,MENU2_ID=OPTION_ID ...]]` FQBN to
|
||||
* `VENDOR:ARCHITECTURE:BOARD_ID` format.
|
||||
* See the details of the `{build.fqbn}` entry in the [specs](https://arduino.github.io/arduino-cli/latest/platform-specification/#global-predefined-properties).
|
||||
*/
|
||||
private sanitizeFqbn(fqbn: string | undefined): string | undefined {
|
||||
if (!fqbn) {
|
||||
return undefined;
|
||||
}
|
||||
const [vendor, arch, id] = fqbn.split(':');
|
||||
return `${vendor}:${arch}:${id}`;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace UploadSketch {
|
||||
@@ -299,7 +298,7 @@ export namespace UploadSketch {
|
||||
export const UPLOAD_SKETCH: Command = {
|
||||
id: 'arduino-upload-sketch',
|
||||
};
|
||||
export const UPLOAD_WITH_CONFIGURATION: Command = {
|
||||
export const UPLOAD_WITH_CONFIGURATION: Command & { label: string } = {
|
||||
id: 'arduino-upload-with-configuration-sketch',
|
||||
label: nls.localize(
|
||||
'arduino/sketch/configureAndUpload',
|
||||
|
@@ -2,8 +2,6 @@ import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import {
|
||||
CoreServiceContribution,
|
||||
Command,
|
||||
@@ -14,27 +12,36 @@ import {
|
||||
} from './contribution';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import { CurrentSketch } from '../../common/protocol/sketches-service-client-impl';
|
||||
import { CoreService } from '../../common/protocol';
|
||||
import { CoreErrorHandler } from './core-error-handler';
|
||||
|
||||
export interface VerifySketchParams {
|
||||
/**
|
||||
* Same as `CoreService.Options.Compile#exportBinaries`
|
||||
*/
|
||||
readonly exportBinaries?: boolean;
|
||||
/**
|
||||
* If `true`, there won't be any UI indication of the verify command. It's `false` by default.
|
||||
*/
|
||||
readonly silent?: boolean;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class VerifySketch extends CoreServiceContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
@inject(CoreErrorHandler)
|
||||
private readonly coreErrorHandler: CoreErrorHandler;
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
protected readonly onDidChangeEmitter = new Emitter<Readonly<void>>();
|
||||
readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
|
||||
protected verifyInProgress = false;
|
||||
private readonly onDidChangeEmitter = new Emitter<void>();
|
||||
private readonly onDidChange = this.onDidChangeEmitter.event;
|
||||
private verifyInProgress = false;
|
||||
|
||||
override registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH, {
|
||||
execute: () => this.verifySketch(),
|
||||
execute: (params?: VerifySketchParams) => this.verifySketch(params),
|
||||
isEnabled: () => !this.verifyInProgress,
|
||||
});
|
||||
registry.registerCommand(VerifySketch.Commands.EXPORT_BINARIES, {
|
||||
execute: () => this.verifySketch(true),
|
||||
execute: () => this.verifySketch({ exportBinaries: true }),
|
||||
isEnabled: () => !this.verifyInProgress,
|
||||
});
|
||||
registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR, {
|
||||
@@ -84,61 +91,87 @@ export class VerifySketch extends CoreServiceContribution {
|
||||
});
|
||||
}
|
||||
|
||||
async verifySketch(exportBinaries?: boolean): Promise<void> {
|
||||
// even with buttons disabled, better to double check if a verify is already in progress
|
||||
protected override handleError(error: unknown): void {
|
||||
this.coreErrorHandler.tryHandle(error);
|
||||
super.handleError(error);
|
||||
}
|
||||
|
||||
private async verifySketch(
|
||||
params?: VerifySketchParams
|
||||
): Promise<CoreService.Options.Compile | undefined> {
|
||||
if (this.verifyInProgress) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// toggle the toolbar button and menu item state.
|
||||
// verifyInProgress will be set to false whether the compilation fails or not
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!CurrentSketch.isValid(sketch)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.verifyInProgress = true;
|
||||
if (!params?.silent) {
|
||||
this.verifyInProgress = true;
|
||||
this.onDidChangeEmitter.fire();
|
||||
}
|
||||
this.coreErrorHandler.reset();
|
||||
this.onDidChangeEmitter.fire();
|
||||
const { boardsConfig } = this.boardsServiceClientImpl;
|
||||
const [fqbn, sourceOverride] = await Promise.all([
|
||||
this.boardsDataStore.appendConfigToFqbn(
|
||||
boardsConfig.selectedBoard?.fqbn
|
||||
|
||||
const options = await this.options(params?.exportBinaries);
|
||||
if (!options) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
await this.doWithProgress({
|
||||
progressText: nls.localize(
|
||||
'arduino/sketch/compile',
|
||||
'Compiling sketch...'
|
||||
),
|
||||
this.sourceOverride(),
|
||||
]);
|
||||
const board = {
|
||||
...boardsConfig.selectedBoard,
|
||||
name: boardsConfig.selectedBoard?.name || '',
|
||||
fqbn,
|
||||
};
|
||||
const verbose = this.preferences.get('arduino.compile.verbose');
|
||||
const compilerWarnings = this.preferences.get('arduino.compile.warnings');
|
||||
const optimizeForDebug =
|
||||
await this.commandService.executeCommand<boolean>(
|
||||
'arduino-is-optimize-for-debug'
|
||||
);
|
||||
this.outputChannelManager.getChannel('Arduino').clear();
|
||||
await this.coreService.compile({
|
||||
sketch,
|
||||
board,
|
||||
optimizeForDebug: Boolean(optimizeForDebug),
|
||||
verbose,
|
||||
exportBinaries,
|
||||
sourceOverride,
|
||||
compilerWarnings,
|
||||
task: (progressId, coreService) =>
|
||||
coreService.compile({
|
||||
...options,
|
||||
progressId,
|
||||
}),
|
||||
});
|
||||
this.messageService.info(
|
||||
nls.localize('arduino/sketch/doneCompiling', 'Done compiling.'),
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
// Returns with the used options for the compilation
|
||||
// so that follow-up tasks (such as upload) can reuse the compiled code.
|
||||
// Note that the `fqbn` is already decorated with the board settings, if any.
|
||||
return options;
|
||||
} catch (e) {
|
||||
this.handleError(e);
|
||||
return undefined;
|
||||
} finally {
|
||||
this.verifyInProgress = false;
|
||||
this.onDidChangeEmitter.fire();
|
||||
if (!params?.silent) {
|
||||
this.onDidChangeEmitter.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async options(
|
||||
exportBinaries?: boolean
|
||||
): Promise<CoreService.Options.Compile | undefined> {
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!CurrentSketch.isValid(sketch)) {
|
||||
return undefined;
|
||||
}
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
const [fqbn, sourceOverride, optimizeForDebug] = await Promise.all([
|
||||
this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn),
|
||||
this.sourceOverride(),
|
||||
this.commandService.executeCommand<boolean>(
|
||||
'arduino-is-optimize-for-debug'
|
||||
),
|
||||
]);
|
||||
const verbose = this.preferences.get('arduino.compile.verbose');
|
||||
const compilerWarnings = this.preferences.get('arduino.compile.warnings');
|
||||
return {
|
||||
sketch,
|
||||
fqbn,
|
||||
optimizeForDebug: Boolean(optimizeForDebug),
|
||||
verbose,
|
||||
exportBinaries,
|
||||
sourceOverride,
|
||||
compilerWarnings,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace VerifySketch {
|
||||
|
@@ -8,6 +8,7 @@
|
||||
"list.inactiveSelectionForeground": "#dae3e3",
|
||||
"list.inactiveSelectionBackground": "#434f54",
|
||||
"list.hoverBackground": "#1f272a",
|
||||
"list.activeSelectionIconForeground": "#0ca1a6",
|
||||
"progressBar.background": "#005c5f",
|
||||
"editor.background": "#1f272a",
|
||||
"editor.foreground": "#dae3e3",
|
||||
@@ -16,6 +17,7 @@
|
||||
"editorCursor.foreground": "#434f54",
|
||||
"editorWhitespace.foreground": "#bfbfbf",
|
||||
"editorWidget.background": "#171e21",
|
||||
"editorWidget.foreground": "#dae3e3",
|
||||
"focusBorder": "#dae3e3",
|
||||
"menubar.selectionBackground": "#ffffff",
|
||||
"menubar.selectionForeground": "#212121",
|
||||
@@ -28,7 +30,7 @@
|
||||
"titleBar.activeBackground": "#171e21",
|
||||
"titleBar.activeForeground": "#dae3e3",
|
||||
"terminal.background": "#000000",
|
||||
"terminal.foreground": "#e0e0e0",
|
||||
"terminal.foreground": "#ffffff",
|
||||
"dropdown.border": "#7fcbcd",
|
||||
"dropdown.background": "#2c353a",
|
||||
"dropdown.foreground": "#dae3e3",
|
||||
@@ -64,7 +66,8 @@
|
||||
"settings.headerForeground": "#dae3e3",
|
||||
"tree.indentGuidesStroke": "#374146",
|
||||
"tab.unfocusedActiveForeground": "#dae3e3",
|
||||
"tab.inactiveBackground": "#171e21"
|
||||
"tab.inactiveBackground": "#171e21",
|
||||
"textLink.foreground": "#0ca1a6"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
|
@@ -8,6 +8,7 @@
|
||||
"list.inactiveSelectionForeground": "#4e5b61",
|
||||
"list.inactiveSelectionBackground": "#dae3e3",
|
||||
"list.hoverBackground": "#ecf1f1",
|
||||
"list.activeSelectionIconForeground": "#008184",
|
||||
"progressBar.background": "#005c5f",
|
||||
"editor.background": "#ffffff",
|
||||
"editor.foreground": "#4e5b61",
|
||||
@@ -16,6 +17,7 @@
|
||||
"editorCursor.foreground": "#434f54",
|
||||
"editorWhitespace.foreground": "#bfbfbf",
|
||||
"editorWidget.background": "#f7f9f9",
|
||||
"editorWidget.foreground": "#4e5b61",
|
||||
"focusBorder": "#7fcbcd",
|
||||
"menubar.selectionBackground": "#ffffff",
|
||||
"menubar.selectionForeground": "#212121",
|
||||
@@ -28,7 +30,7 @@
|
||||
"titleBar.activeBackground": "#006d70",
|
||||
"titleBar.activeForeground": "#f7f9f9",
|
||||
"terminal.background": "#000000",
|
||||
"terminal.foreground": "#e0e0e0",
|
||||
"terminal.foreground": "#ffffff",
|
||||
"dropdown.border": "#dae3e3",
|
||||
"dropdown.background": "#ffffff",
|
||||
"dropdown.foreground": "#4e5b61",
|
||||
@@ -64,7 +66,8 @@
|
||||
"settings.headerForeground": "#4e5b61",
|
||||
"tree.indentGuidesStroke": "#dae3e3",
|
||||
"tab.unfocusedActiveForeground": "#4e5b61",
|
||||
"tab.inactiveBackground": "#ecf1f1"
|
||||
"tab.inactiveBackground": "#ecf1f1",
|
||||
"textLink.foreground": "#008184"
|
||||
},
|
||||
"tokenColors": [
|
||||
{
|
||||
|
@@ -19,6 +19,7 @@ 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/common';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
|
||||
@injectable()
|
||||
export class UploadCertificateDialogWidget extends ReactWidget {
|
||||
@@ -37,6 +38,9 @@ export class UploadCertificateDialogWidget extends ReactWidget {
|
||||
@inject(ArduinoFirmwareUploader)
|
||||
protected readonly arduinoFirmwareUploader: ArduinoFirmwareUploader;
|
||||
|
||||
@inject(FrontendApplicationStateService)
|
||||
private readonly appStateService: FrontendApplicationStateService;
|
||||
|
||||
protected certificates: string[] = [];
|
||||
protected updatableFqbns: string[] = [];
|
||||
protected availableBoards: AvailableBoard[] = [];
|
||||
@@ -66,10 +70,12 @@ export class UploadCertificateDialogWidget extends ReactWidget {
|
||||
}
|
||||
});
|
||||
|
||||
this.arduinoFirmwareUploader.updatableBoards().then((fqbns) => {
|
||||
this.updatableFqbns = fqbns;
|
||||
this.update();
|
||||
});
|
||||
this.appStateService.reachedState('ready').then(() =>
|
||||
this.arduinoFirmwareUploader.updatableBoards().then((fqbns) => {
|
||||
this.updatableFqbns = fqbns;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
this.boardsServiceClient.onAvailableBoardsChanged((availableBoards) => {
|
||||
this.availableBoards = availableBoards;
|
||||
|
@@ -201,12 +201,7 @@ export class SettingsComponent extends React.Component<
|
||||
<div className="flex-line">
|
||||
<select
|
||||
className="theia-select"
|
||||
value={
|
||||
ThemeService.get()
|
||||
.getThemes()
|
||||
.find(({ id }) => id === this.state.themeId)?.label ||
|
||||
nls.localize('arduino/common/unknown', 'Unknown')
|
||||
}
|
||||
value={ThemeService.get().getCurrentTheme().label}
|
||||
onChange={this.themeDidChange}
|
||||
>
|
||||
{ThemeService.get()
|
||||
@@ -591,6 +586,9 @@ export class SettingsComponent extends React.Component<
|
||||
const theme = ThemeService.get().getThemes()[selectedIndex];
|
||||
if (theme) {
|
||||
this.setState({ themeId: theme.id });
|
||||
if (ThemeService.get().getCurrentTheme().id !== theme.id) {
|
||||
ThemeService.get().setCurrentTheme(theme.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -16,6 +16,7 @@ import { SettingsComponent } from './settings-component';
|
||||
import { AsyncLocalizationProvider } from '@theia/core/lib/common/i18n/localization';
|
||||
import { AdditionalUrls } from '../../../common/protocol';
|
||||
import { AbstractDialog } from '../../theia/dialogs/dialogs';
|
||||
import { ThemeService } from '@theia/core/lib/browser/theming';
|
||||
|
||||
@injectable()
|
||||
export class SettingsWidget extends ReactWidget {
|
||||
@@ -118,6 +119,17 @@ export class SettingsDialog extends AbstractDialog<Promise<Settings>> {
|
||||
|
||||
this.widget.activate();
|
||||
}
|
||||
|
||||
override async open(): Promise<Promise<Settings> | undefined> {
|
||||
const themeIdBeforeOpen = ThemeService.get().getCurrentTheme().id;
|
||||
const result = await super.open();
|
||||
if (!result) {
|
||||
if (ThemeService.get().getCurrentTheme().id !== themeIdBeforeOpen) {
|
||||
ThemeService.get().setCurrentTheme(themeIdBeforeOpen);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class AdditionalUrlsDialog extends AbstractDialog<string[]> {
|
||||
|
@@ -16,64 +16,30 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
|
||||
const { value, setSettingsStateValue, step, maxValue, minValue, classNames } =
|
||||
props;
|
||||
|
||||
const [stepUpDisabled, setStepUpDisabled] = React.useState(false);
|
||||
const [stepDownDisabled, setStepDownDisabled] = React.useState(false);
|
||||
const clamp = (value: number, min: number, max: number): number => {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
};
|
||||
|
||||
const onStepUp = (): void => {
|
||||
const valueRoundedToScale = Math.ceil(value / step) * step;
|
||||
const onStep = (
|
||||
roundingOperation: 'ceil' | 'floor',
|
||||
stepOperation: (a: number, b: number) => number
|
||||
): void => {
|
||||
const valueRoundedToScale = Math[roundingOperation](value / step) * step;
|
||||
const calculatedValue =
|
||||
valueRoundedToScale === value ? value + step : valueRoundedToScale;
|
||||
const newValue = limitValueByCondition(
|
||||
calculatedValue,
|
||||
maxValue,
|
||||
calculatedValue >= maxValue,
|
||||
disableStepUp
|
||||
);
|
||||
valueRoundedToScale === value
|
||||
? stepOperation(value, step)
|
||||
: valueRoundedToScale;
|
||||
const newValue = clamp(calculatedValue, minValue, maxValue);
|
||||
|
||||
setSettingsStateValue(newValue);
|
||||
};
|
||||
|
||||
const onStepUp = (): void => {
|
||||
onStep('ceil', (a: number, b: number) => a + b);
|
||||
};
|
||||
|
||||
const onStepDown = (): void => {
|
||||
const valueRoundedToScale = Math.floor(value / step) * step;
|
||||
const calculatedValue =
|
||||
valueRoundedToScale === value ? value - step : valueRoundedToScale;
|
||||
const newValue = limitValueByCondition(
|
||||
calculatedValue,
|
||||
minValue,
|
||||
calculatedValue <= minValue,
|
||||
disableStepDown
|
||||
);
|
||||
|
||||
setSettingsStateValue(newValue);
|
||||
};
|
||||
|
||||
const limitValueByCondition = (
|
||||
calculatedValue: number,
|
||||
limitedValue: number,
|
||||
condition: boolean,
|
||||
onConditionTrue: () => void,
|
||||
onConditionFalse = enableButtons
|
||||
): number => {
|
||||
if (condition) {
|
||||
onConditionTrue();
|
||||
return limitedValue;
|
||||
} else {
|
||||
onConditionFalse();
|
||||
return calculatedValue;
|
||||
}
|
||||
};
|
||||
|
||||
const enableButtons = (): void => {
|
||||
setStepUpDisabled(false);
|
||||
setStepDownDisabled(false);
|
||||
};
|
||||
|
||||
const disableStepUp = (): void => {
|
||||
setStepUpDisabled(true);
|
||||
};
|
||||
|
||||
const disableStepDown = (): void => {
|
||||
setStepDownDisabled(true);
|
||||
onStep('floor', (a: number, b: number) => a - b);
|
||||
};
|
||||
|
||||
const onUserInput = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
@@ -86,34 +52,14 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
|
||||
const number = Number(eventValue);
|
||||
|
||||
if (!isNaN(number) && number !== value) {
|
||||
let newValue;
|
||||
if (number > value) {
|
||||
newValue = limitValueByCondition(
|
||||
number,
|
||||
maxValue,
|
||||
number >= maxValue,
|
||||
disableStepUp
|
||||
);
|
||||
} else {
|
||||
newValue = limitValueByCondition(
|
||||
number,
|
||||
minValue,
|
||||
number <= minValue,
|
||||
disableStepDown
|
||||
);
|
||||
}
|
||||
const newValue = clamp(number, minValue, maxValue);
|
||||
|
||||
setSettingsStateValue(newValue);
|
||||
}
|
||||
};
|
||||
|
||||
// the component does not unmount when we close the settings dialog
|
||||
// in theia which necessitates the below useEffect
|
||||
React.useEffect(() => {
|
||||
if (value > minValue && value < maxValue) {
|
||||
enableButtons();
|
||||
}
|
||||
}, [value, minValue, maxValue]);
|
||||
const upDisabled = value >= maxValue;
|
||||
const downDisabled = value <= minValue;
|
||||
|
||||
return (
|
||||
<div className="settings-step-input-container">
|
||||
@@ -127,14 +73,14 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
|
||||
<div className="settings-step-input-buttons-container">
|
||||
<button
|
||||
className="settings-step-input-button settings-step-input-up-button"
|
||||
disabled={stepUpDisabled}
|
||||
disabled={upDisabled}
|
||||
onClick={onStepUp}
|
||||
>
|
||||
▾
|
||||
</button>
|
||||
<button
|
||||
className="settings-step-input-button"
|
||||
disabled={stepDownDisabled}
|
||||
disabled={downDisabled}
|
||||
onClick={onStepDown}
|
||||
>
|
||||
▾
|
||||
|
@@ -111,9 +111,11 @@ export class SettingsService {
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
const settings = await this.loadSettings();
|
||||
this._settings = deepClone(settings);
|
||||
this.ready.resolve();
|
||||
this.appStateService.reachedState('ready').then(async () => {
|
||||
const settings = await this.loadSettings();
|
||||
this._settings = deepClone(settings);
|
||||
this.ready.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
protected async loadSettings(): Promise<Settings> {
|
||||
@@ -139,7 +141,10 @@ export class SettingsService {
|
||||
this.preferenceService.get<number>(FONT_SIZE_SETTING, 12),
|
||||
this.preferenceService.get<string>(
|
||||
'workbench.colorTheme',
|
||||
'arduino-theme'
|
||||
window.matchMedia &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'arduino-theme-dark'
|
||||
: 'arduino-theme'
|
||||
),
|
||||
this.preferenceService.get<Settings.AutoSave>(
|
||||
AUTO_SAVE_SETTING,
|
||||
|
@@ -49,3 +49,14 @@
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc .arduino-select__option--is-selected {
|
||||
outline: 1px solid var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .arduino-select__option--is-focused {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ div.dialogContent.select-board-dialog > div.head .title {
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.02em;
|
||||
font-size: 1.2em;
|
||||
color: var(--theia-arduino-branding-primary);
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected {
|
||||
}
|
||||
|
||||
div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
color: var(--theia-arduino-branding-primary);
|
||||
color: var(--theia-list-activeSelectionIconForeground);
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .search,
|
||||
@@ -43,7 +43,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
display: flex;
|
||||
color: var(--theia-editor-foreground);
|
||||
color: var(--theia-input-foreground);
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .search input:focus {
|
||||
@@ -66,7 +66,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
}
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .container .content .title {
|
||||
color: #7f8c8d;
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
padding: 0px 0px 10px 0px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
|
||||
#select-board-dialog .selectBoardContainer .body .container .content .loading {
|
||||
font-size: var(--theia-ui-font-size1);
|
||||
color: var(--theia-arduino-branding-secondary);
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
padding: 10px 5px 10px 10px;
|
||||
text-transform: uppercase;
|
||||
/* The max, min-height comes from `.body .list` 200px + 47px top padding - 2 * 10px top padding */
|
||||
@@ -148,6 +148,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
background: var(--theia-arduino-toolbar-dropdown-background);
|
||||
border-radius: 1px;
|
||||
color: var(--theia-arduino-toolbar-dropdown-label);
|
||||
border: 1px solid var(--theia-arduino-toolbar-dropdown-border);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
height: 28px;
|
||||
@@ -164,10 +165,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item--protocol {
|
||||
color: var(--theia-arduino-toolbar-dropdown-label);
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item--protocol ,
|
||||
.arduino-boards-dropdown-item--protocol {
|
||||
color: var(--theia-arduino-toolbar-dropdown-label);
|
||||
}
|
||||
@@ -180,9 +178,6 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
}
|
||||
|
||||
.arduino-boards-toolbar-item--label {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -208,6 +203,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
.arduino-boards-dropdown-list--items-container {
|
||||
overflow: auto;
|
||||
max-height: 404px;
|
||||
background: var(--theia-arduino-toolbar-dropdown-background);
|
||||
}
|
||||
|
||||
.arduino-boards-dropdown-list--items-container::-webkit-scrollbar {
|
||||
@@ -226,6 +222,7 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
}
|
||||
|
||||
.arduino-boards-dropdown-item--label {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -248,8 +245,8 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
}
|
||||
|
||||
.arduino-boards-dropdown-item--selected
|
||||
.arduino-boards-dropdown-item--port-label {
|
||||
color: var(--theia-arduino-toolbar-dropdown-label);
|
||||
.arduino-boards-dropdown-item--port-label {
|
||||
color: var(--theia-arduino-toolbar-dropdown-label);
|
||||
}
|
||||
|
||||
.arduino-boards-dropdown-item--selected .fa {
|
||||
@@ -261,6 +258,16 @@ div#select-board-dialog .selectBoardContainer .body .list .item.selected i {
|
||||
}
|
||||
|
||||
.arduino-board-dropdown-footer {
|
||||
color: var(--theia-arduino-branding-primary);
|
||||
border-top: 1px solid var(--theia-arduino-toolbar-dropdown-border);
|
||||
color: var(--theia-secondaryButton-foreground);
|
||||
border-top: 1px solid var(--theia-dropdown-border);
|
||||
}
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc #select-board-dialog .selectBoardContainer .body .list .item:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc div#select-board-dialog .selectBoardContainer .body .list .item.selected {
|
||||
outline: 1px solid var(--theia-focusBorder);
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
}
|
||||
.certificate-uploader-dialog .arduino-select__control {
|
||||
height: 31px;
|
||||
background: var(--theia-menubar-selectionBackground) !important;
|
||||
background: var(--theia-dropdown-background) !important;
|
||||
}
|
||||
|
||||
.certificate-uploader-dialog .dialogRow > button{
|
||||
@@ -15,9 +15,10 @@
|
||||
}
|
||||
|
||||
.certificate-uploader-dialog .certificate-list {
|
||||
border: 1px solid #BDC7C7;
|
||||
border: 1px solid var(--theia-editorWidget-border);
|
||||
border-radius: 2px;;
|
||||
background: var(--theia-menubar-selectionBackground) !important;
|
||||
color: var(--theia-editor-foreground);
|
||||
background-color: var(--theia-editor-background);
|
||||
overflow: auto;
|
||||
height: 120px;
|
||||
flex: 1;
|
||||
@@ -60,9 +61,10 @@
|
||||
|
||||
.certificate-add {
|
||||
padding: 16px;
|
||||
background-color: var(--theia-list-hoverBackground);
|
||||
border-radius: 3px;
|
||||
border: 1px solid #BDC7C7;
|
||||
border: 1px solid var(--theia-editorWidget-border);
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
background-color: var(--theia-editorWidget-background);
|
||||
}
|
||||
|
||||
.certificate-add input {
|
||||
@@ -71,4 +73,4 @@
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -96,7 +96,7 @@
|
||||
|
||||
.cloud-sketchbook-welcome > .item .link {
|
||||
cursor: pointer;
|
||||
color: var(--theia-arduino-branding-primary);
|
||||
color: var(--theia-textLink-foreground);
|
||||
}
|
||||
|
||||
.pull-sketch-icon {
|
||||
|
@@ -17,7 +17,7 @@
|
||||
font-weight: 500;
|
||||
background-color: transparent;
|
||||
font-size: var(--theia-ui-font-size2);
|
||||
color: var(--theia-list-inactiveSelectionForeground);
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.monaco-list-row.show-file-icons.focused {
|
||||
background-color: #d6ebff;
|
||||
background-color: var(--theia-quickInputList-focusBackground);
|
||||
}
|
||||
|
||||
.monaco-editor .view-overlays .compiler-error {
|
||||
|
@@ -27,9 +27,9 @@
|
||||
}
|
||||
|
||||
.ide-updater-dialog .changelog-container {
|
||||
color: var(--theia-dropdown-foreground);
|
||||
background-color: var(--theia-dropdown-background);
|
||||
border: 1px solid var(--theia-tree-indentGuidesStroke);
|
||||
color: var(--theia-editor-foreground);
|
||||
background-color: var(--theia-editor-background);
|
||||
border: 1px solid var(--theia-editorWidget-border);
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
height: 180px;
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
|
||||
.ide-updater-dialog .changelog-container a {
|
||||
color: #018184;
|
||||
color: var(--theia-textLink-foreground);
|
||||
}
|
||||
|
||||
.ide-updater-dialog .changelog-container a:hover {
|
||||
@@ -48,13 +48,13 @@
|
||||
}
|
||||
|
||||
.ide-updater-dialog .changelog-container code {
|
||||
background: #ecf1f1;
|
||||
background: var(--theia-textBlockQuote-background);
|
||||
border-radius: 2px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.ide-updater-dialog .changelog-container a code {
|
||||
color: #018184;
|
||||
color: var(--theia-textLink-foreground);
|
||||
}
|
||||
|
||||
.ide-updater-dialog .buttons-container {
|
||||
|
@@ -135,3 +135,23 @@ button.secondary[disabled], .theia-button.secondary[disabled] {
|
||||
.fa-reload {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc button.theia-button:hover,
|
||||
.hc-black.hc-theia.theia-hc .theia-button:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc button.theia-button,
|
||||
.hc-black.hc-theia.theia-hc .theia-button,
|
||||
.hc-black.hc-theia.theia-hc button.theia-button.secondary {
|
||||
border: 1px solid var(--theia-button-border);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .theia-notification-list-item:hover:not(:focus) {
|
||||
background-color: var(--theia-notifications-background);
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
@@ -145,3 +145,14 @@ https://github.com/arduino/arduino-pro-ide/issues/82 */
|
||||
.component-list-item a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc .component-list-item .header .installed:hover:before {
|
||||
background-color: transparent;
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .component-list-item .header .installed:before {
|
||||
border: 1px solid var(--theia-button-border);
|
||||
}
|
||||
|
@@ -173,18 +173,73 @@
|
||||
|
||||
/* Output */
|
||||
.theia-output .editor-container {
|
||||
background-color: var(--theia-arduino-output-background);
|
||||
background-color: var(--theia-terminal-background);
|
||||
}
|
||||
|
||||
.theia-output .monaco-editor .lines-content.monaco-editor-background {
|
||||
background-color: var(--theia-arduino-output-background);
|
||||
background-color: var(--theia-terminal-background);
|
||||
}
|
||||
|
||||
.theia-output .monaco-editor .lines-content.monaco-editor-background .view-lines .view-line .mtk1:not(.theia-output-error):not(.theia-output-warning) {
|
||||
color: var(--theia-arduino-output-foreground);
|
||||
color: var(--theia-terminal-foreground);
|
||||
}
|
||||
|
||||
.theia-output .monaco-editor .margin {
|
||||
border-right: none;
|
||||
background-color: var(--theia-arduino-output-background);
|
||||
background-color: var(--theia-terminal-background);
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div {
|
||||
background: var(--theia-arduino-toolbar-button-background);
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div.toggle-serial-plotter,
|
||||
.hc-black.hc-theia.theia-hc .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div.toggle-serial-monitor {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .item.arduino-tool-item.toggled .arduino-verify-sketch--toolbar,
|
||||
.hc-black.hc-theia.theia-hc .item.arduino-tool-item.toggled .arduino-upload-sketch--toolbar {
|
||||
background-color: var(--theia-arduino-toolbar-button-background) !important;
|
||||
outline: 1px solid var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .arduino-boards-dropdown-item:hover {
|
||||
background: var(--theia-dropdown-background);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .arduino-boards-dropdown-item:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc #theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current {
|
||||
outline: 1px solid var(--theia-focusBorder);
|
||||
outline-offset: -4px;
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc #theia-main-content-panel .p-TabBar .p-TabBar-tab:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
outline-offset: -4px;
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .quick-input-list .monaco-list-row.focused {
|
||||
outline: 1px dotted var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .quick-input-list .monaco-list-row:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .quick-input-widget {
|
||||
outline: 1px solid var(--theia-contrastBorder);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.progress-bar--outer {
|
||||
background: #e5e5e5;
|
||||
background: var(--theia-editorWidget-background);
|
||||
border-radius: 11px;
|
||||
height: 6px;
|
||||
position: relative;
|
||||
@@ -13,7 +13,7 @@
|
||||
.progress-bar--inner {
|
||||
transition: width 1s;
|
||||
height: 100%;
|
||||
background: #008184;
|
||||
background: var(--theia-progressBar-background);
|
||||
border-radius: 11px;
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,11 @@
|
||||
|
||||
#arduino-settings-dialog-container > .dialogBlock > .dialogContent {
|
||||
justify-content: flex-start;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#arduino-settings-dialog-container > .dialogBlock > .dialogControl {
|
||||
padding: 16px 0 26px;
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .content {
|
||||
@@ -61,8 +66,19 @@
|
||||
color: var(--theia-textLink-activeForeground);
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .react-tabs__tab--selected {
|
||||
background: var(--theia-editorWidget-background);
|
||||
border-color: var(--theia-tab-activeBorder);
|
||||
color: var(--theia-tab-activeForeground);
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .react-tabs__tab-list {
|
||||
border-color: var(--theia-tab-activeBorder);
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .react-tabs__tab-panel {
|
||||
padding-bottom: 25px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.arduino-settings-dialog .react-tabs__tab-list {
|
||||
|
@@ -45,7 +45,7 @@
|
||||
.active-sketch {
|
||||
font-weight: 500;
|
||||
background-color: var(--theia-list-activeSelectionBackground) !important;
|
||||
color: var(--theia-list-inactiveSelectionForeground) !important;
|
||||
color: var(--theia-list-activeSelectionForeground) !important;
|
||||
|
||||
}
|
||||
|
||||
@@ -69,4 +69,21 @@
|
||||
.theia-Tree:focus .theia-TreeNode.theia-mod-selected,
|
||||
.theia-Tree .ReactVirtualized__List:focus .theia-TreeNode.theia-mod-selected {
|
||||
background: var(--theia-list-inactiveSelectionBackground);
|
||||
color: var(--theia-list-inactiveSelectionForeground) !important;
|
||||
}
|
||||
|
||||
|
||||
/* High Contrast Theme rules */
|
||||
/* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/
|
||||
.hc-black.hc-theia.theia-hc .theia-TreeNode:hover {
|
||||
outline: 1px dashed var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .theia-Tree .theia-TreeNode.theia-mod-selected {
|
||||
outline: 1px dotted var(--theia-focusBorder);
|
||||
}
|
||||
|
||||
.hc-black.hc-theia.theia-hc .theia-Tree:focus .theia-TreeNode.theia-mod-selected,
|
||||
.hc-black.hc-theia.theia-hc .theia-Tree .ReactVirtualized__List:focus .theia-TreeNode.theia-mod-selected {
|
||||
outline: 1px solid var(--theia-focusBorder);
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
}
|
||||
|
||||
.user-fields-dialog-content .field-label {
|
||||
color: #2c353a;
|
||||
color: var(--theia-editorWidget-foreground);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
@@ -29,4 +29,4 @@
|
||||
|
||||
.user-fields-dialog-content .button-container {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
@@ -10,28 +10,35 @@ import {
|
||||
import {
|
||||
ApplicationShell as TheiaApplicationShell,
|
||||
DockPanel,
|
||||
DockPanelRenderer as TheiaDockPanelRenderer,
|
||||
Panel,
|
||||
TabBar,
|
||||
Widget,
|
||||
SHELL_TABBAR_CONTEXT_MENU,
|
||||
} from '@theia/core/lib/browser';
|
||||
import { Sketch } from '../../../common/protocol';
|
||||
import { SaveAsSketch } from '../../contributions/save-as-sketch';
|
||||
import { CurrentSketch, SketchesServiceClientImpl } from '../../../common/protocol/sketches-service-client-impl';
|
||||
import {
|
||||
CurrentSketch,
|
||||
SketchesServiceClientImpl,
|
||||
} from '../../../common/protocol/sketches-service-client-impl';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { ToolbarAwareTabBar } from './tab-bars';
|
||||
|
||||
@injectable()
|
||||
export class ApplicationShell extends TheiaApplicationShell {
|
||||
@inject(CommandService)
|
||||
protected readonly commandService: CommandService;
|
||||
private readonly commandService: CommandService;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
private readonly messageService: MessageService;
|
||||
|
||||
@inject(SketchesServiceClientImpl)
|
||||
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
private readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
|
||||
@inject(ConnectionStatusService)
|
||||
protected readonly connectionStatusService: ConnectionStatusService;
|
||||
private readonly connectionStatusService: ConnectionStatusService;
|
||||
|
||||
protected override track(widget: Widget): void {
|
||||
super.track(widget);
|
||||
@@ -43,7 +50,7 @@ export class ApplicationShell extends TheiaApplicationShell {
|
||||
this.sketchesServiceClient.currentSketch().then((sketch) => {
|
||||
if (CurrentSketch.isValid(sketch)) {
|
||||
if (!this.isSketchFile(widget.editor.uri, sketch.uri)) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
if (Sketch.isInSketch(widget.editor.uri, sketch)) {
|
||||
widget.title.closable = false;
|
||||
@@ -54,11 +61,11 @@ export class ApplicationShell extends TheiaApplicationShell {
|
||||
}
|
||||
|
||||
private isSketchFile(uri: URI, sketchUriString: string): boolean {
|
||||
const sketchUri = new URI(sketchUriString);
|
||||
if (uri.parent.isEqual(sketchUri)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
const sketchUri = new URI(sketchUriString);
|
||||
if (uri.parent.isEqual(sketchUri)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
override async addWidget(
|
||||
@@ -120,15 +127,41 @@ export class ApplicationShell extends TheiaApplicationShell {
|
||||
}
|
||||
}
|
||||
|
||||
export class DockPanelRenderer extends TheiaDockPanelRenderer {
|
||||
override createTabBar(): TabBar<Widget> {
|
||||
const renderer = this.tabBarRendererFactory();
|
||||
// `ToolbarAwareTabBar` is from IDE2 and not from Theia. Check the imports.
|
||||
const tabBar = new ToolbarAwareTabBar(
|
||||
this.tabBarToolbarRegistry,
|
||||
this.tabBarToolbarFactory,
|
||||
this.breadcrumbsRendererFactory,
|
||||
{
|
||||
renderer,
|
||||
// Scroll bar options
|
||||
handlers: ['drag-thumb', 'keyboard', 'wheel', 'touch'],
|
||||
useBothWheelAxes: true,
|
||||
scrollXMarginOffset: 4,
|
||||
suppressScrollY: true,
|
||||
}
|
||||
);
|
||||
this.tabBarClasses.forEach((c) => tabBar.addClass(c));
|
||||
renderer.tabBar = tabBar;
|
||||
tabBar.disposed.connect(() => renderer.dispose());
|
||||
renderer.contextMenuPath = SHELL_TABBAR_CONTEXT_MENU;
|
||||
tabBar.currentChanged.connect(this.onCurrentTabChanged, this);
|
||||
return tabBar;
|
||||
}
|
||||
}
|
||||
|
||||
const originalHandleEvent = DockPanel.prototype.handleEvent;
|
||||
|
||||
DockPanel.prototype.handleEvent = function (event) {
|
||||
switch (event.type) {
|
||||
case 'p-dragenter':
|
||||
case 'p-dragleave':
|
||||
case 'p-dragover':
|
||||
case 'p-drop':
|
||||
return;
|
||||
case 'p-dragenter':
|
||||
case 'p-dragleave':
|
||||
case 'p-dragover':
|
||||
case 'p-drop':
|
||||
return;
|
||||
}
|
||||
originalHandleEvent.bind(this)(event);
|
||||
};
|
||||
|
@@ -0,0 +1,10 @@
|
||||
import { DefaultWindowService as TheiaDefaultWindowService } from '@theia/core/lib/browser/window/default-window-service';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { DefaultWindowService } from './default-window-service';
|
||||
import { WindowServiceExt } from './window-service-ext';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(DefaultWindowService).toSelf().inSingletonScope();
|
||||
rebind(TheiaDefaultWindowService).toService(DefaultWindowService);
|
||||
bind(WindowServiceExt).toService(DefaultWindowService);
|
||||
});
|
@@ -13,6 +13,7 @@ import {
|
||||
import { ArduinoDaemon } from '../../../common/protocol';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import debounce = require('lodash.debounce');
|
||||
|
||||
@injectable()
|
||||
export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService {
|
||||
@@ -36,10 +37,11 @@ export class FrontendConnectionStatusService extends TheiaFrontendConnectionStat
|
||||
this.notificationCenter.onDaemonDidStop(
|
||||
() => (this.connectedPort = undefined)
|
||||
);
|
||||
this.wsConnectionProvider.onIncomingMessageActivity(() => {
|
||||
const refresh = debounce(() => {
|
||||
this.updateStatus(!!this.connectedPort);
|
||||
this.schedulePing();
|
||||
});
|
||||
}, this.options.offlineTimeout - 10);
|
||||
this.wsConnectionProvider.onIncomingMessageActivity(() => refresh());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,17 @@
|
||||
import { DefaultWindowService as TheiaDefaultWindowService } from '@theia/core/lib/browser/window/default-window-service';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { WindowServiceExt } from './window-service-ext';
|
||||
|
||||
@injectable()
|
||||
export class DefaultWindowService
|
||||
extends TheiaDefaultWindowService
|
||||
implements WindowServiceExt
|
||||
{
|
||||
/**
|
||||
* The default implementation always resolves to `true`.
|
||||
* IDE2 does not use it. It's currently an electron-only app.
|
||||
*/
|
||||
async isFirstWindow(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
}
|
13
arduino-ide-extension/src/browser/theia/core/status-bar.ts
Normal file
13
arduino-ide-extension/src/browser/theia/core/status-bar.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { StatusBarImpl as TheiaStatusBarImpl } from '@theia/core/lib/browser';
|
||||
|
||||
@injectable()
|
||||
export class StatusBarImpl extends TheiaStatusBarImpl {
|
||||
override async removeElement(id: string): Promise<void> {
|
||||
await this.ready;
|
||||
if (this.entries.delete(id)) {
|
||||
// Unlike Theia, IDE2 updates the status bar only if the element to remove was among the entries. Otherwise, it's a NOOP.
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,13 @@
|
||||
import { TabBar } from '@theia/core/shared/@phosphor/widgets';
|
||||
import type { TabBar } from '@theia/core/shared/@phosphor/widgets';
|
||||
import { Saveable } from '@theia/core/lib/browser/saveable';
|
||||
import { TabBarRenderer as TheiaTabBarRenderer } from '@theia/core/lib/browser/shell/tab-bars';
|
||||
import {
|
||||
TabBarRenderer as TheiaTabBarRenderer,
|
||||
ToolbarAwareTabBar as TheiaToolbarAwareTabBar,
|
||||
} from '@theia/core/lib/browser/shell/tab-bars';
|
||||
import debounce = require('lodash.debounce');
|
||||
|
||||
export class TabBarRenderer extends TheiaTabBarRenderer {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
override createTabClass(data: TabBar.IRenderData<any>): string {
|
||||
let className = super.createTabClass(data);
|
||||
if (!data.title.closable && Saveable.isDirty(data.title.owner)) {
|
||||
@@ -16,3 +21,16 @@ export class TabBarRenderer extends TheiaTabBarRenderer {
|
||||
// Context menus are empty, so they have been removed
|
||||
};
|
||||
}
|
||||
|
||||
export class ToolbarAwareTabBar extends TheiaToolbarAwareTabBar {
|
||||
protected override async updateBreadcrumbs(): Promise<void> {
|
||||
// NOOP
|
||||
// IDE2 does not use breadcrumbs.
|
||||
}
|
||||
|
||||
private readonly doUpdateToolbar = debounce(() => super.updateToolbar(), 500);
|
||||
protected override updateToolbar(): void {
|
||||
// Unlike Theia, IDE2 debounces the toolbar updates with 500ms
|
||||
this.doUpdateToolbar();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,7 @@
|
||||
export const WindowServiceExt = Symbol('WindowServiceExt');
|
||||
export interface WindowServiceExt {
|
||||
/**
|
||||
* Returns with a promise that resolves to `true` if the current window is the first window.
|
||||
*/
|
||||
isFirstWindow(): Promise<boolean>;
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { EditorWidget } from '@theia/editor/lib/browser';
|
||||
import { LabelProvider } from '@theia/core/lib/browser';
|
||||
import type { NavigatableWidgetOptions } from '@theia/core/lib/browser';
|
||||
import { EditorWidgetFactory as TheiaEditorWidgetFactory } from '@theia/editor/lib/browser/editor-widget-factory';
|
||||
import {
|
||||
CurrentSketch,
|
||||
@@ -13,16 +13,16 @@ import { nls } from '@theia/core/lib/common';
|
||||
@injectable()
|
||||
export class EditorWidgetFactory extends TheiaEditorWidgetFactory {
|
||||
@inject(SketchesService)
|
||||
protected readonly sketchesService: SketchesService;
|
||||
private readonly sketchesService: SketchesService;
|
||||
|
||||
@inject(SketchesServiceClientImpl)
|
||||
protected readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
private readonly sketchesServiceClient: SketchesServiceClientImpl;
|
||||
|
||||
@inject(LabelProvider)
|
||||
protected override readonly labelProvider: LabelProvider;
|
||||
|
||||
protected override async createEditor(uri: URI): Promise<EditorWidget> {
|
||||
const widget = await super.createEditor(uri);
|
||||
protected override async createEditor(
|
||||
uri: URI,
|
||||
options: NavigatableWidgetOptions
|
||||
): Promise<EditorWidget> {
|
||||
const widget = await super.createEditor(uri, options);
|
||||
return this.maybeUpdateCaption(widget);
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,15 @@
|
||||
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
inject,
|
||||
injectable,
|
||||
postConstruct,
|
||||
} from '@theia/core/shared/inversify';
|
||||
import { Diagnostic } from 'vscode-languageserver-types';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { ILogger } from '@theia/core';
|
||||
import { Marker } from '@theia/markers/lib/common/marker';
|
||||
import { ProblemManager as TheiaProblemManager } from '@theia/markers/lib/browser/problem/problem-manager';
|
||||
import { ConfigService } from '../../../common/protocol/config-service';
|
||||
import debounce = require('lodash.debounce');
|
||||
|
||||
@injectable()
|
||||
export class ProblemManager extends TheiaProblemManager {
|
||||
@@ -37,4 +42,12 @@ export class ProblemManager extends TheiaProblemManager {
|
||||
}
|
||||
return super.setMarkers(uri, owner, data);
|
||||
}
|
||||
|
||||
private readonly debouncedFireOnDidChangeMakers = debounce(
|
||||
(uri: URI) => this.onDidChangeMarkersEmitter.fire(uri),
|
||||
500
|
||||
);
|
||||
protected override fireOnDidChangeMarkers(uri: URI): void {
|
||||
this.debouncedFireOnDidChangeMakers(uri);
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,29 @@
|
||||
import * as React from '@theia/core/shared/react';
|
||||
import * as ReactDOM from '@theia/core/shared/react-dom';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
inject,
|
||||
injectable,
|
||||
postConstruct,
|
||||
} from '@theia/core/shared/inversify';
|
||||
import { NotificationCenterComponent } from './notification-center-component';
|
||||
import { NotificationToastsComponent } from './notification-toasts-component';
|
||||
import { NotificationsRenderer as TheiaNotificationsRenderer } from '@theia/messages/lib/browser/notifications-renderer';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
|
||||
@injectable()
|
||||
export class NotificationsRenderer extends TheiaNotificationsRenderer {
|
||||
@inject(FrontendApplicationStateService)
|
||||
private readonly appStateService: FrontendApplicationStateService;
|
||||
|
||||
@postConstruct()
|
||||
protected override init(): void {
|
||||
// Unlike Theia, IDE2 renders the notification area only when the app is ready.
|
||||
this.appStateService.reachedState('ready').then(() => {
|
||||
this.createOverlayContainer();
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
|
||||
protected override render(): void {
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
|
@@ -5,3 +5,11 @@
|
||||
export function setURL(url: URL, data: any = {}): void {
|
||||
history.pushState(data, '', url);
|
||||
}
|
||||
|
||||
/**
|
||||
* If available from the `window` object, then it means, the IDE2 has successfully patched the `MonacoThemingService#init` static method,
|
||||
* and can wait the custom theme registration.
|
||||
*/
|
||||
export const MonacoThemeServiceIsReady = Symbol(
|
||||
'@arduino-ide#monaco-theme-service-is-ready'
|
||||
);
|
||||
|
@@ -5,6 +5,7 @@ import { CommandService } from '@theia/core/lib/common/command';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { ConfirmDialog } from '@theia/core/lib/browser/dialogs';
|
||||
import { Searchable } from '../../../common/protocol/searchable';
|
||||
import { ExecuteWithProgress } from '../../../common/protocol/progressible';
|
||||
import { Installable } from '../../../common/protocol/installable';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
import { SearchBar } from './search-bar';
|
||||
@@ -111,7 +112,7 @@ export class FilterableListContainer<
|
||||
version: Installable.Version
|
||||
): Promise<void> {
|
||||
const { install, searchable } = this.props;
|
||||
await Installable.doWithProgress({
|
||||
await ExecuteWithProgress.doWithProgress({
|
||||
...this.props,
|
||||
progressText:
|
||||
nls.localize('arduino/common/processing', 'Processing') +
|
||||
@@ -137,7 +138,7 @@ export class FilterableListContainer<
|
||||
return;
|
||||
}
|
||||
const { uninstall, searchable } = this.props;
|
||||
await Installable.doWithProgress({
|
||||
await ExecuteWithProgress.doWithProgress({
|
||||
...this.props,
|
||||
progressText:
|
||||
nls.localize('arduino/common/processing', 'Processing') +
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { ApplicationError } from '@theia/core/lib/common/application-error';
|
||||
import type { Location } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import type {
|
||||
Board,
|
||||
BoardUserField,
|
||||
Port,
|
||||
} from '../../common/protocol/boards-service';
|
||||
@@ -60,45 +59,39 @@ export namespace CoreError {
|
||||
export const CoreServicePath = '/services/core-service';
|
||||
export const CoreService = Symbol('CoreService');
|
||||
export interface CoreService {
|
||||
compile(
|
||||
options: CoreService.Compile.Options &
|
||||
Readonly<{
|
||||
exportBinaries?: boolean;
|
||||
compilerWarnings?: CompilerWarnings;
|
||||
}>
|
||||
): Promise<void>;
|
||||
upload(options: CoreService.Upload.Options): Promise<void>;
|
||||
uploadUsingProgrammer(options: CoreService.Upload.Options): Promise<void>;
|
||||
burnBootloader(options: CoreService.Bootloader.Options): Promise<void>;
|
||||
compile(options: CoreService.Options.Compile): Promise<void>;
|
||||
upload(options: CoreService.Options.Upload): Promise<void>;
|
||||
burnBootloader(options: CoreService.Options.Bootloader): Promise<void>;
|
||||
}
|
||||
|
||||
export namespace CoreService {
|
||||
export namespace Compile {
|
||||
export interface Options {
|
||||
export namespace Options {
|
||||
export interface Base {
|
||||
readonly fqbn?: string | undefined;
|
||||
readonly verbose: boolean; // TODO: (API) why not optional with a default false?
|
||||
readonly progressId?: string;
|
||||
}
|
||||
export interface SketchBased {
|
||||
readonly sketch: Sketch;
|
||||
readonly board?: Board;
|
||||
readonly optimizeForDebug: boolean;
|
||||
readonly verbose: boolean;
|
||||
readonly sourceOverride: Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Upload {
|
||||
export interface Options extends Compile.Options {
|
||||
export interface BoardBased {
|
||||
readonly port?: Port;
|
||||
readonly programmer?: Programmer | undefined;
|
||||
readonly verify: boolean;
|
||||
/**
|
||||
* For the _Verify after upload_ setting.
|
||||
*/
|
||||
readonly verify: boolean; // TODO: (API) why not optional with false as the default value?
|
||||
}
|
||||
export interface Compile extends Base, SketchBased {
|
||||
readonly optimizeForDebug: boolean; // TODO: (API) make this optional
|
||||
readonly sourceOverride: Record<string, string>; // TODO: (API) make this optional
|
||||
readonly exportBinaries?: boolean;
|
||||
readonly compilerWarnings?: CompilerWarnings;
|
||||
}
|
||||
export interface Upload extends Base, SketchBased, BoardBased {
|
||||
readonly userFields: BoardUserField[];
|
||||
readonly usingProgrammer?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Bootloader {
|
||||
export interface Options {
|
||||
readonly board?: Board;
|
||||
readonly port?: Port;
|
||||
readonly programmer?: Programmer | undefined;
|
||||
readonly verbose: boolean;
|
||||
readonly verify: boolean;
|
||||
}
|
||||
export interface Bootloader extends Base, BoardBased {}
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,6 @@
|
||||
import * as semver from 'semver';
|
||||
import type { Progress } from '@theia/core/lib/common/message-service-protocol';
|
||||
import {
|
||||
CancellationToken,
|
||||
CancellationTokenSource,
|
||||
} from '@theia/core/lib/common/cancellation';
|
||||
import { naturalCompare } from './../utils';
|
||||
import { ExecuteWithProgress } from './progressible';
|
||||
import { naturalCompare } from '../utils';
|
||||
import type { ArduinoComponent } from './arduino-component';
|
||||
import type { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import type { ResponseServiceClient } from './response-service';
|
||||
@@ -32,7 +28,7 @@ export namespace Installable {
|
||||
/**
|
||||
* Most recent version comes first, then the previous versions. (`1.8.1`, `1.6.3`, `1.6.2`, `1.6.1` and so on.)
|
||||
*/
|
||||
export const COMPARATOR = (left: Version, right: Version) => {
|
||||
export const COMPARATOR = (left: Version, right: Version): number => {
|
||||
if (semver.valid(left) && semver.valid(right)) {
|
||||
return semver.compare(left, right);
|
||||
}
|
||||
@@ -50,7 +46,7 @@ export namespace Installable {
|
||||
version: Installable.Version;
|
||||
}): Promise<void> {
|
||||
const { item, version } = options;
|
||||
return doWithProgress({
|
||||
return ExecuteWithProgress.doWithProgress({
|
||||
...options,
|
||||
progressText: `Processing ${item.name}:${version}`,
|
||||
run: ({ progressId }) =>
|
||||
@@ -71,7 +67,7 @@ export namespace Installable {
|
||||
item: T;
|
||||
}): Promise<void> {
|
||||
const { item } = options;
|
||||
return doWithProgress({
|
||||
return ExecuteWithProgress.doWithProgress({
|
||||
...options,
|
||||
progressText: `Processing ${item.name}${
|
||||
item.installedVersion ? `:${item.installedVersion}` : ''
|
||||
@@ -83,51 +79,4 @@ export namespace Installable {
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function doWithProgress(options: {
|
||||
run: ({ progressId }: { progressId: string }) => Promise<void>;
|
||||
messageService: MessageService;
|
||||
responseService: ResponseServiceClient;
|
||||
progressText: string;
|
||||
}): Promise<void> {
|
||||
return withProgress(
|
||||
options.progressText,
|
||||
options.messageService,
|
||||
async (progress, _) => {
|
||||
const progressId = progress.id;
|
||||
const toDispose = options.responseService.onProgressDidChange(
|
||||
(progressMessage) => {
|
||||
if (progressId === progressMessage.progressId) {
|
||||
const { message, work } = progressMessage;
|
||||
progress.report({ message, work });
|
||||
}
|
||||
}
|
||||
);
|
||||
try {
|
||||
options.responseService.clearOutput();
|
||||
await options.run({ progressId });
|
||||
} finally {
|
||||
toDispose.dispose();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function withProgress(
|
||||
text: string,
|
||||
messageService: MessageService,
|
||||
cb: (progress: Progress, token: CancellationToken) => Promise<void>
|
||||
): Promise<void> {
|
||||
const cancellationSource = new CancellationTokenSource();
|
||||
const { token } = cancellationSource;
|
||||
const progress = await messageService.showProgress(
|
||||
{ text, options: { cancelable: false } },
|
||||
() => cancellationSource.cancel()
|
||||
);
|
||||
try {
|
||||
await cb(progress, token);
|
||||
} finally {
|
||||
progress.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
60
arduino-ide-extension/src/common/protocol/progressible.ts
Normal file
60
arduino-ide-extension/src/common/protocol/progressible.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import type { CancellationToken } from '@theia/core/lib/common/cancellation';
|
||||
import { CancellationTokenSource } from '@theia/core/lib/common/cancellation';
|
||||
import type { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import type { Progress } from '@theia/core/lib/common/message-service-protocol';
|
||||
import type { ResponseServiceClient } from './response-service';
|
||||
|
||||
export namespace ExecuteWithProgress {
|
||||
export async function doWithProgress<T>(options: {
|
||||
run: ({ progressId }: { progressId: string }) => Promise<T>;
|
||||
messageService: MessageService;
|
||||
responseService: ResponseServiceClient;
|
||||
progressText: string;
|
||||
keepOutput?: boolean;
|
||||
}): Promise<T> {
|
||||
return withProgress(
|
||||
options.progressText,
|
||||
options.messageService,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async (progress, _token) => {
|
||||
const progressId = progress.id;
|
||||
const toDispose = options.responseService.onProgressDidChange(
|
||||
(progressMessage) => {
|
||||
if (progressId === progressMessage.progressId) {
|
||||
const { message, work } = progressMessage;
|
||||
progress.report({ message, work });
|
||||
}
|
||||
}
|
||||
);
|
||||
try {
|
||||
if (!options.keepOutput) {
|
||||
options.responseService.clearOutput();
|
||||
}
|
||||
const result = await options.run({ progressId });
|
||||
return result;
|
||||
} finally {
|
||||
toDispose.dispose();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function withProgress<T>(
|
||||
text: string,
|
||||
messageService: MessageService,
|
||||
cb: (progress: Progress, token: CancellationToken) => Promise<T>
|
||||
): Promise<T> {
|
||||
const cancellationSource = new CancellationTokenSource();
|
||||
const { token } = cancellationSource;
|
||||
const progress = await messageService.showProgress(
|
||||
{ text, options: { cancelable: false } },
|
||||
() => cancellationSource.cancel()
|
||||
);
|
||||
try {
|
||||
const result = await cb(progress, token);
|
||||
return result;
|
||||
} finally {
|
||||
progress.cancel();
|
||||
}
|
||||
}
|
||||
}
|
@@ -46,5 +46,5 @@ export interface ResponseService {
|
||||
export const ResponseServiceClient = Symbol('ResponseServiceClient');
|
||||
export interface ResponseServiceClient extends ResponseService {
|
||||
onProgressDidChange: Event<ProgressMessage>;
|
||||
clearOutput: () => void;
|
||||
clearOutput: () => void; // TODO: this should not belong here.
|
||||
}
|
||||
|
@@ -1,14 +1,7 @@
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { ElectronMainMenuFactory as TheiaElectronMainMenuFactory } from '@theia/core/lib/electron-browser/menu/electron-main-menu-factory';
|
||||
import { ElectronMenuContribution as TheiaElectronMenuContribution } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution';
|
||||
import { ElectronIpcConnectionProvider } from '@theia/core/lib/electron-browser/messaging/electron-ipc-connection-provider';
|
||||
import {
|
||||
SplashService,
|
||||
splashServicePath,
|
||||
} from '../../../electron-common/splash-service';
|
||||
import { MainMenuManager } from '../../../common/main-menu-manager';
|
||||
import { ElectronWindowService } from '../../electron-window-service';
|
||||
import { ElectronMainMenuFactory } from './electron-main-menu-factory';
|
||||
import { ElectronMenuContribution } from './electron-menu-contribution';
|
||||
import { nls } from '@theia/core/lib/common/nls';
|
||||
@@ -16,39 +9,31 @@ import { nls } from '@theia/core/lib/common/nls';
|
||||
import * as remote from '@theia/core/electron-shared/@electron/remote';
|
||||
import * as dialogs from '@theia/core/lib/browser/dialogs';
|
||||
|
||||
|
||||
Object.assign(dialogs, {
|
||||
confirmExit: async () => {
|
||||
const messageBoxResult = await remote.dialog.showMessageBox(
|
||||
remote.getCurrentWindow(),
|
||||
{
|
||||
message: nls.localize('theia/core/quitMessage', 'Any unsaved changes will not be saved.'),
|
||||
title: nls.localize('theia/core/quitTitle', 'Are you sure you want to quit?'),
|
||||
message: nls.localize(
|
||||
'theia/core/quitMessage',
|
||||
'Any unsaved changes will not be saved.'
|
||||
),
|
||||
title: nls.localize(
|
||||
'theia/core/quitTitle',
|
||||
'Are you sure you want to quit?'
|
||||
),
|
||||
type: 'question',
|
||||
buttons: [
|
||||
dialogs.Dialog.CANCEL,
|
||||
dialogs.Dialog.YES,
|
||||
],
|
||||
buttons: [dialogs.Dialog.CANCEL, dialogs.Dialog.YES],
|
||||
}
|
||||
)
|
||||
);
|
||||
return messageBoxResult.response === 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ElectronMenuContribution).toSelf().inSingletonScope();
|
||||
bind(MainMenuManager).toService(ElectronMenuContribution);
|
||||
rebind(TheiaElectronMenuContribution).to(ElectronMenuContribution);
|
||||
rebind(TheiaElectronMenuContribution).toService(ElectronMenuContribution);
|
||||
bind(ElectronMainMenuFactory).toSelf().inSingletonScope();
|
||||
rebind(TheiaElectronMainMenuFactory).toService(ElectronMainMenuFactory);
|
||||
bind(ElectronWindowService).toSelf().inSingletonScope();
|
||||
rebind(WindowService).toService(ElectronWindowService);
|
||||
bind(SplashService)
|
||||
.toDynamicValue((context) =>
|
||||
ElectronIpcConnectionProvider.createProxy(
|
||||
context.container,
|
||||
splashServicePath
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
});
|
||||
|
@@ -0,0 +1,23 @@
|
||||
import { WindowService } from '@theia/core/lib/browser/window/window-service';
|
||||
import { ElectronIpcConnectionProvider } from '@theia/core/lib/electron-browser/messaging/electron-ipc-connection-provider';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { WindowServiceExt } from '../../../browser/theia/core/window-service-ext';
|
||||
import {
|
||||
ElectronMainWindowServiceExt,
|
||||
electronMainWindowServiceExtPath,
|
||||
} from '../../../electron-common/electron-main-window-service-ext';
|
||||
import { ElectronWindowService } from './electron-window-service';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ElectronWindowService).toSelf().inSingletonScope();
|
||||
rebind(WindowService).toService(ElectronWindowService);
|
||||
bind(WindowServiceExt).toService(ElectronWindowService);
|
||||
bind(ElectronMainWindowServiceExt)
|
||||
.toDynamicValue(({ container }) =>
|
||||
ElectronIpcConnectionProvider.createProxy(
|
||||
container,
|
||||
electronMainWindowServiceExtPath
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
});
|
@@ -1,30 +1,34 @@
|
||||
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
|
||||
import * as remote from '@theia/core/electron-shared/@electron/remote';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import {
|
||||
ConnectionStatus,
|
||||
ConnectionStatusService,
|
||||
} 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/common';
|
||||
import { ElectronWindowService as TheiaElectronWindowService } from '@theia/core/lib/electron-browser/window/electron-window-service';
|
||||
import {
|
||||
inject,
|
||||
injectable,
|
||||
postConstruct,
|
||||
} from '@theia/core/shared/inversify';
|
||||
import { WindowServiceExt } from '../../../browser/theia/core/window-service-ext';
|
||||
import { ElectronMainWindowServiceExt } from '../../../electron-common/electron-main-window-service-ext';
|
||||
|
||||
@injectable()
|
||||
export class ElectronWindowService extends TheiaElectronWindowService {
|
||||
export class ElectronWindowService
|
||||
extends TheiaElectronWindowService
|
||||
implements WindowServiceExt
|
||||
{
|
||||
@inject(ConnectionStatusService)
|
||||
protected readonly connectionStatusService: ConnectionStatusService;
|
||||
private readonly connectionStatusService: ConnectionStatusService;
|
||||
|
||||
@inject(SplashService)
|
||||
protected readonly splashService: SplashService;
|
||||
|
||||
@inject(FrontendApplicationStateService)
|
||||
protected readonly appStateService: FrontendApplicationStateService;
|
||||
@inject(ElectronMainWindowServiceExt)
|
||||
private readonly mainWindowServiceExt: ElectronMainWindowServiceExt;
|
||||
|
||||
@postConstruct()
|
||||
protected override init(): void {
|
||||
this.appStateService
|
||||
.reachedAnyState('initialized_layout')
|
||||
.then(() => this.splashService.requestClose());
|
||||
// NOOP
|
||||
// Does not listen on Theia's `window.zoomLevel` changes.
|
||||
// TODO: IDE2 must switch to the Theia preferences and drop the custom one.
|
||||
}
|
||||
|
||||
protected shouldUnload(): boolean {
|
||||
@@ -55,4 +59,15 @@ export class ElectronWindowService extends TheiaElectronWindowService {
|
||||
});
|
||||
return response === 0; // 'Yes', close the window.
|
||||
}
|
||||
|
||||
private _firstWindow: boolean | undefined;
|
||||
async isFirstWindow(): Promise<boolean> {
|
||||
if (this._firstWindow === undefined) {
|
||||
const windowId = remote.getCurrentWindow().id; // This is expensive and synchronous so we check it once per FE.
|
||||
this._firstWindow = await this.mainWindowServiceExt.isFirstWindow(
|
||||
windowId
|
||||
);
|
||||
}
|
||||
return this._firstWindow;
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
export const electronMainWindowServiceExtPath = '/services/electron-window-ext';
|
||||
export const ElectronMainWindowServiceExt = Symbol(
|
||||
'ElectronMainWindowServiceExt'
|
||||
);
|
||||
export interface ElectronMainWindowServiceExt {
|
||||
isFirstWindow(windowId: number): Promise<boolean>;
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
export const splashServicePath = '/services/splash-service';
|
||||
export const SplashService = Symbol('SplashService');
|
||||
export interface SplashService {
|
||||
requestClose(): Promise<void>;
|
||||
}
|
@@ -1,31 +1,26 @@
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import { JsonRpcConnectionHandler } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { ElectronConnectionHandler } from '@theia/core/lib/electron-common/messaging/electron-connection-handler';
|
||||
import { ElectronMainWindowService } from '@theia/core/lib/electron-common/electron-main-window-service';
|
||||
import { ElectronConnectionHandler } from '@theia/core/lib/electron-common/messaging/electron-connection-handler';
|
||||
import {
|
||||
ElectronMainApplication as TheiaElectronMainApplication,
|
||||
ElectronMainApplicationContribution,
|
||||
} from '@theia/core/lib/electron-main/electron-main-application';
|
||||
import {
|
||||
SplashService,
|
||||
splashServicePath,
|
||||
} from '../electron-common/splash-service';
|
||||
import { SplashServiceImpl } from './splash/splash-service-impl';
|
||||
import { ElectronMainApplication } from './theia/electron-main-application';
|
||||
import { ElectronMainWindowServiceImpl } from './theia/electron-main-window-service';
|
||||
import { TheiaElectronWindow as DefaultTheiaElectronWindow } from '@theia/core/lib/electron-main/theia-electron-window';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
IDEUpdater,
|
||||
IDEUpdaterClient,
|
||||
IDEUpdaterPath,
|
||||
} from '../common/protocol/ide-updater';
|
||||
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
|
||||
import { TheiaElectronWindow } from './theia/theia-electron-window';
|
||||
import { TheiaElectronWindow as DefaultTheiaElectronWindow } from '@theia/core/lib/electron-main/theia-electron-window';
|
||||
import { SurveyNotificationServiceImpl } from '../node/survey-service-impl';
|
||||
import {
|
||||
SurveyNotificationService,
|
||||
SurveyNotificationServicePath,
|
||||
} from '../common/protocol/survey-service';
|
||||
ElectronMainWindowServiceExt,
|
||||
electronMainWindowServiceExtPath,
|
||||
} from '../electron-common/electron-main-window-service-ext';
|
||||
import { ElectronMainWindowServiceExtImpl } from './electron-main-window-service-ext-impl';
|
||||
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
|
||||
import { ElectronMainApplication } from './theia/electron-main-application';
|
||||
import { ElectronMainWindowServiceImpl } from './theia/electron-main-window-service';
|
||||
import { TheiaElectronWindow } from './theia/theia-electron-window';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ElectronMainApplication).toSelf().inSingletonScope();
|
||||
@@ -34,17 +29,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ElectronMainWindowServiceImpl).toSelf().inSingletonScope();
|
||||
rebind(ElectronMainWindowService).toService(ElectronMainWindowServiceImpl);
|
||||
|
||||
bind(SplashServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SplashService).toService(SplashServiceImpl);
|
||||
bind(ElectronConnectionHandler)
|
||||
.toDynamicValue(
|
||||
(context) =>
|
||||
new JsonRpcConnectionHandler(splashServicePath, () =>
|
||||
context.container.get(SplashService)
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
|
||||
// IDE updater bindings
|
||||
bind(IDEUpdaterImpl).toSelf().inSingletonScope();
|
||||
bind(IDEUpdater).toService(IDEUpdaterImpl);
|
||||
@@ -67,19 +51,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(TheiaElectronWindow).toSelf();
|
||||
rebind(DefaultTheiaElectronWindow).toService(TheiaElectronWindow);
|
||||
|
||||
// Survey notification bindings
|
||||
bind(SurveyNotificationServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SurveyNotificationService).toService(SurveyNotificationServiceImpl);
|
||||
bind(ElectronMainApplicationContribution).toService(
|
||||
SurveyNotificationService
|
||||
);
|
||||
bind(ElectronMainWindowServiceExt)
|
||||
.to(ElectronMainWindowServiceExtImpl)
|
||||
.inSingletonScope();
|
||||
bind(ElectronConnectionHandler)
|
||||
.toDynamicValue(
|
||||
(context) =>
|
||||
new JsonRpcConnectionHandler(SurveyNotificationServicePath, () =>
|
||||
context.container.get<SurveyNotificationService>(
|
||||
SurveyNotificationService
|
||||
)
|
||||
new JsonRpcConnectionHandler(electronMainWindowServiceExtPath, () =>
|
||||
context.container.get(ElectronMainWindowServiceExt)
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
|
@@ -0,0 +1,15 @@
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { ElectronMainWindowServiceExt } from '../electron-common/electron-main-window-service-ext';
|
||||
import { ElectronMainApplication } from './theia/electron-main-application';
|
||||
|
||||
@injectable()
|
||||
export class ElectronMainWindowServiceExtImpl
|
||||
implements ElectronMainWindowServiceExt
|
||||
{
|
||||
@inject(ElectronMainApplication)
|
||||
private readonly app: ElectronMainApplication;
|
||||
|
||||
async isFirstWindow(windowId: number): Promise<boolean> {
|
||||
return this.app.firstWindowId === windowId;
|
||||
}
|
||||
}
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Troy McKinnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// Copied from https://raw.githubusercontent.com/trodi/electron-splashscreen/2f5052a133be021cbf9a438d0ef4719cd1796b75/index.ts
|
||||
|
||||
/**
|
||||
* Module handles configurable splashscreen to show while app is loading.
|
||||
*/
|
||||
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
/**
|
||||
* When splashscreen was shown.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreenTimestamp = 0;
|
||||
/**
|
||||
* Splashscreen is loaded and ready to show.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreenReady = false;
|
||||
/**
|
||||
* Main window has been loading for a min amount of time.
|
||||
* @ignore
|
||||
*/
|
||||
let slowStartup = false;
|
||||
/**
|
||||
* True when expected work is complete and we've closed splashscreen, else user prematurely closed splashscreen.
|
||||
* @ignore
|
||||
*/
|
||||
let done = false;
|
||||
/**
|
||||
* Show splashscreen if criteria are met.
|
||||
* @ignore
|
||||
*/
|
||||
const showSplash = () => {
|
||||
if (splashScreen && splashScreenReady && slowStartup) {
|
||||
splashScreen.show();
|
||||
splashScreenTimestamp = Date.now();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Close splashscreen / show main screen. Ensure screen is visible for a min amount of time.
|
||||
* @ignore
|
||||
*/
|
||||
const closeSplashScreen = (main: Electron.BrowserWindow, min: number): void => {
|
||||
if (splashScreen) {
|
||||
const timeout = min - (Date.now() - splashScreenTimestamp);
|
||||
setTimeout(() => {
|
||||
done = true;
|
||||
if (splashScreen) {
|
||||
splashScreen.isDestroyed() || splashScreen.close(); // Avoid `Error: Object has been destroyed` (#19)
|
||||
splashScreen = null;
|
||||
}
|
||||
if (!main.isDestroyed()) {
|
||||
main.show();
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
};
|
||||
/** `electron-splashscreen` config object. */
|
||||
export interface Config {
|
||||
/** Options for the window that is loading and having a splashscreen tied to. */
|
||||
windowOpts: Electron.BrowserWindowConstructorOptions;
|
||||
/**
|
||||
* URL to the splashscreen template. This is the path to an `HTML` or `SVG` file.
|
||||
* If you want to simply show a `PNG`, wrap it in an `HTML` file.
|
||||
*/
|
||||
templateUrl: string;
|
||||
|
||||
/**
|
||||
* Full set of browser window options for the splashscreen. We override key attributes to
|
||||
* make it look & feel like a splashscreen; the rest is up to you!
|
||||
*/
|
||||
splashScreenOpts: Electron.BrowserWindowConstructorOptions;
|
||||
/** Number of ms the window will load before splashscreen appears (default: 500ms). */
|
||||
delay?: number;
|
||||
/** Minimum ms the splashscreen will be visible (default: 500ms). */
|
||||
minVisible?: number;
|
||||
/** Close window that is loading if splashscreen is closed by user (default: true). */
|
||||
closeWindow?: boolean;
|
||||
}
|
||||
/**
|
||||
* The actual splashscreen browser window.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreen: Electron.BrowserWindow | null;
|
||||
/**
|
||||
* Initializes a splashscreen that will show/hide smartly (and handle show/hiding of main window).
|
||||
* @param config - Configures splashscreen
|
||||
* @returns {BrowserWindow} the main browser window ready for loading
|
||||
*/
|
||||
export const initSplashScreen = async (
|
||||
config: Config,
|
||||
windowFactory: (
|
||||
options: Electron.BrowserViewConstructorOptions
|
||||
) => Promise<BrowserWindow>,
|
||||
onCloseRequested?: Event<void>
|
||||
): Promise<BrowserWindow> => {
|
||||
const xConfig: Required<Config> = {
|
||||
windowOpts: config.windowOpts,
|
||||
templateUrl: config.templateUrl,
|
||||
splashScreenOpts: config.splashScreenOpts,
|
||||
delay: config.delay ?? 500,
|
||||
minVisible: config.minVisible ?? 500,
|
||||
closeWindow: config.closeWindow ?? true,
|
||||
};
|
||||
xConfig.splashScreenOpts.center = true;
|
||||
xConfig.splashScreenOpts.frame = false;
|
||||
xConfig.windowOpts.show = false;
|
||||
const window = await windowFactory(xConfig.windowOpts);
|
||||
splashScreen = new BrowserWindow(xConfig.splashScreenOpts);
|
||||
splashScreen.loadURL(`file://${xConfig.templateUrl}`);
|
||||
xConfig.closeWindow &&
|
||||
splashScreen.on('close', () => {
|
||||
done || window.close();
|
||||
});
|
||||
// Splashscreen is fully loaded and ready to view.
|
||||
splashScreen.webContents.on('did-finish-load', () => {
|
||||
splashScreenReady = true;
|
||||
showSplash();
|
||||
});
|
||||
// Startup is taking enough time to show a splashscreen.
|
||||
setTimeout(() => {
|
||||
slowStartup = true;
|
||||
showSplash();
|
||||
}, xConfig.delay);
|
||||
if (onCloseRequested) {
|
||||
onCloseRequested(() => closeSplashScreen(window, xConfig.minVisible));
|
||||
} else {
|
||||
window.webContents.on('did-finish-load', () => {
|
||||
closeSplashScreen(window, xConfig.minVisible);
|
||||
});
|
||||
}
|
||||
window.on('closed', () => closeSplashScreen(window, 0)); // XXX: close splash when main window is closed
|
||||
return window;
|
||||
};
|
@@ -1,20 +0,0 @@
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { SplashService } from '../../electron-common/splash-service';
|
||||
|
||||
@injectable()
|
||||
export class SplashServiceImpl implements SplashService {
|
||||
protected requested = false;
|
||||
protected readonly onCloseRequestedEmitter = new Emitter<void>();
|
||||
|
||||
get onCloseRequested(): Event<void> {
|
||||
return this.onCloseRequestedEmitter.event;
|
||||
}
|
||||
|
||||
async requestClose(): Promise<void> {
|
||||
if (!this.requested) {
|
||||
this.requested = true;
|
||||
this.onCloseRequestedEmitter.fire();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
.container {
|
||||
width: auto;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 95%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<p><img src="splash.png"></p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 103 KiB |
@@ -1,18 +1,15 @@
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
contentTracing,
|
||||
ipcMain,
|
||||
screen,
|
||||
Event as ElectronEvent,
|
||||
} from '@theia/core/electron-shared/electron';
|
||||
import { fork } from 'child_process';
|
||||
import { AddressInfo } from 'net';
|
||||
import { join, dirname } from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import { initSplashScreen } from '../splash/splash-screen';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token';
|
||||
import { FrontendApplicationConfig } from '@theia/application-package/lib/application-props';
|
||||
@@ -20,7 +17,6 @@ import {
|
||||
ElectronMainApplication as TheiaElectronMainApplication,
|
||||
ElectronMainExecutionParams,
|
||||
} from '@theia/core/lib/electron-main/electron-main-application';
|
||||
import { SplashServiceImpl } from '../splash/splash-service-impl';
|
||||
import { URI } from '@theia/core/shared/vscode-uri';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import * as os from '@theia/core/lib/common/os';
|
||||
@@ -42,14 +38,6 @@ interface WorkspaceOptions {
|
||||
|
||||
const WORKSPACES = 'workspaces';
|
||||
|
||||
/**
|
||||
* Purely a dev thing. If you start the app with the `--nosplash` argument,
|
||||
* then you won't have the splash screen (which is always on top :confused:) and can debug the app at startup.
|
||||
* Note: if you start the app from VS Code with the `App (Electron)` config, the splash screen will be disabled.
|
||||
*/
|
||||
const APP_STARTED_WITH_NOSPLASH =
|
||||
typeof process !== 'undefined' && process.argv.indexOf('--nosplash') !== -1;
|
||||
|
||||
/**
|
||||
* If the app is started with `--open-devtools` argument, the `Dev Tools` will be opened.
|
||||
*/
|
||||
@@ -66,11 +54,9 @@ const APP_STARTED_WITH_CONTENT_TRACE =
|
||||
|
||||
@injectable()
|
||||
export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
protected startup = false;
|
||||
protected openFilePromise = new Deferred();
|
||||
|
||||
@inject(SplashServiceImpl)
|
||||
protected readonly splashService: SplashServiceImpl;
|
||||
private startup = false;
|
||||
private _firstWindowId: number | undefined;
|
||||
private openFilePromise = new Deferred();
|
||||
|
||||
override async start(config: FrontendApplicationConfig): Promise<void> {
|
||||
// Explicitly set the app name to have better menu items on macOS. ("About", "Hide", and "Quit")
|
||||
@@ -142,7 +128,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
})();
|
||||
}
|
||||
|
||||
attachFileAssociations() {
|
||||
private attachFileAssociations(): void {
|
||||
// OSX: register open-file event
|
||||
if (os.isOSX) {
|
||||
app.on('open-file', async (event, uri) => {
|
||||
@@ -158,7 +144,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
}
|
||||
}
|
||||
|
||||
protected async isValidSketchPath(uri: string): Promise<boolean | undefined> {
|
||||
private async isValidSketchPath(uri: string): Promise<boolean | undefined> {
|
||||
return typeof uri === 'string' && (await fs.pathExists(uri));
|
||||
}
|
||||
|
||||
@@ -201,7 +187,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
}
|
||||
}
|
||||
|
||||
protected async launchFromArgs(
|
||||
private async launchFromArgs(
|
||||
params: ElectronMainExecutionParams
|
||||
): Promise<boolean> {
|
||||
// Copy to prevent manipulation of original array
|
||||
@@ -223,7 +209,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected async openSketch(
|
||||
private async openSketch(
|
||||
workspace: WorkspaceOptions | string
|
||||
): Promise<BrowserWindow> {
|
||||
const options = await this.getLastWindowOptions();
|
||||
@@ -257,7 +243,8 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
}
|
||||
|
||||
protected override getTitleBarStyle(
|
||||
config: FrontendApplicationConfig
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_config: FrontendApplicationConfig
|
||||
): 'native' | 'custom' {
|
||||
return 'native';
|
||||
}
|
||||
@@ -287,73 +274,17 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
super.onSecondInstance(event, argv, cwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this rather than creating `BrowserWindow` instances from scratch, since some security parameters need to be set, this method will do it.
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
override async createWindow(
|
||||
asyncOptions: MaybePromise<TheiaBrowserWindowOptions> = this.getDefaultTheiaWindowOptions()
|
||||
): Promise<BrowserWindow> {
|
||||
let options = await asyncOptions;
|
||||
options = this.avoidOverlap(options);
|
||||
let electronWindow: BrowserWindow | undefined;
|
||||
if (this.windows.size || APP_STARTED_WITH_NOSPLASH) {
|
||||
electronWindow = await this.doCreateWindow(options);
|
||||
} else {
|
||||
const { bounds } = screen.getDisplayNearestPoint(
|
||||
screen.getCursorScreenPoint()
|
||||
);
|
||||
const splashHeight = 450;
|
||||
const splashWidth = 600;
|
||||
const splashY = Math.floor(bounds.y + (bounds.height - splashHeight) / 2);
|
||||
const splashX = Math.floor(bounds.x + (bounds.width - splashWidth) / 2);
|
||||
const splashScreenOpts: BrowserWindowConstructorOptions = {
|
||||
height: splashHeight,
|
||||
width: splashWidth,
|
||||
x: splashX,
|
||||
y: splashY,
|
||||
transparent: true,
|
||||
alwaysOnTop: true,
|
||||
focusable: false,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
hasShadow: false,
|
||||
resizable: false,
|
||||
};
|
||||
electronWindow = await initSplashScreen(
|
||||
{
|
||||
windowOpts: options,
|
||||
templateUrl: join(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'src',
|
||||
'electron-main',
|
||||
'splash',
|
||||
'static',
|
||||
'splash.html'
|
||||
),
|
||||
delay: 0,
|
||||
minVisible: 2000,
|
||||
splashScreenOpts,
|
||||
},
|
||||
(windowOptions) => this.doCreateWindow(windowOptions),
|
||||
this.splashService.onCloseRequested
|
||||
);
|
||||
}
|
||||
return electronWindow;
|
||||
}
|
||||
|
||||
private async doCreateWindow(
|
||||
options: TheiaBrowserWindowOptions
|
||||
): Promise<BrowserWindow> {
|
||||
const electronWindow = await super.createWindow(options);
|
||||
const electronWindow = await super.createWindow(asyncOptions);
|
||||
if (APP_STARTED_WITH_DEV_TOOLS) {
|
||||
electronWindow.webContents.openDevTools();
|
||||
}
|
||||
this.attachListenersToWindow(electronWindow);
|
||||
if (this._firstWindowId === undefined) {
|
||||
this._firstWindowId = electronWindow.id;
|
||||
}
|
||||
return electronWindow;
|
||||
}
|
||||
|
||||
@@ -389,7 +320,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
});
|
||||
event.newGuest = new BrowserWindow(options);
|
||||
event.newGuest.setMenu(null);
|
||||
event.newGuest?.on('closed', (e: any) => {
|
||||
event.newGuest?.on('closed', () => {
|
||||
electronWindow?.webContents.send('CLOSE_CHILD_WINDOW');
|
||||
});
|
||||
event.newGuest?.loadURL(url);
|
||||
@@ -462,9 +393,9 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
}
|
||||
}
|
||||
|
||||
protected closedWorkspaces: WorkspaceOptions[] = [];
|
||||
private closedWorkspaces: WorkspaceOptions[] = [];
|
||||
|
||||
protected attachClosedWorkspace(window: BrowserWindow): void {
|
||||
private attachClosedWorkspace(window: BrowserWindow): void {
|
||||
// Since the `before-quit` event is only fired when closing the *last* window
|
||||
// We need to keep track of recently closed windows/workspaces manually
|
||||
window.on('close', () => {
|
||||
@@ -522,4 +453,8 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
get browserWindows(): BrowserWindow[] {
|
||||
return Array.from(this.windows.values()).map(({ window }) => window);
|
||||
}
|
||||
|
||||
get firstWindowId(): number | undefined {
|
||||
return this._firstWindowId;
|
||||
}
|
||||
}
|
||||
|
@@ -76,7 +76,7 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
|
||||
fqbn: firmware.board_fqbn,
|
||||
};
|
||||
try {
|
||||
await this.monitorManager.notifyUploadStarted(board, port);
|
||||
await this.monitorManager.notifyUploadStarted(board.fqbn, port);
|
||||
output = await this.runCommand([
|
||||
'firmware',
|
||||
'flash',
|
||||
@@ -90,7 +90,7 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
|
||||
} catch (e) {
|
||||
throw e;
|
||||
} finally {
|
||||
await this.monitorManager.notifyUploadFinished(board, port);
|
||||
await this.monitorManager.notifyUploadFinished(board.fqbn, port);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ import {
|
||||
} from '../common/protocol/authentication-service';
|
||||
import { ArduinoFirmwareUploaderImpl } from './arduino-firmware-uploader-impl';
|
||||
import { PlotterBackendContribution } from './plotter/plotter-backend-contribution';
|
||||
import { ArduinoLocalizationContribution } from './arduino-localization-contribution';
|
||||
import { ArduinoLocalizationContribution } from './i18n/arduino-localization-contribution';
|
||||
import { LocalizationContribution } from '@theia/core/lib/node/i18n/localization-contribution';
|
||||
import { MonitorManagerProxyImpl } from './monitor-manager-proxy-impl';
|
||||
import { MonitorManager, MonitorManagerName } from './monitor-manager';
|
||||
@@ -102,6 +102,13 @@ import WebSocketProviderImpl from './web-socket/web-socket-provider-impl';
|
||||
import { WebSocketProvider } from './web-socket/web-socket-provider';
|
||||
import { ClangFormatter } from './clang-formatter';
|
||||
import { FormatterPath } from '../common/protocol/formatter';
|
||||
import { LocalizationBackendContribution } from './i18n/localization-backend-contribution';
|
||||
import { LocalizationBackendContribution as TheiaLocalizationBackendContribution } from '@theia/core/lib/node/i18n/localization-backend-contribution';
|
||||
import { SurveyNotificationServiceImpl } from './survey-service-impl';
|
||||
import {
|
||||
SurveyNotificationService,
|
||||
SurveyNotificationServicePath,
|
||||
} from '../common/protocol/survey-service';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(BackendApplication).toSelf().inSingletonScope();
|
||||
@@ -395,4 +402,21 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(BackendApplicationContribution).toService(PlotterBackendContribution);
|
||||
bind(ArduinoLocalizationContribution).toSelf().inSingletonScope();
|
||||
bind(LocalizationContribution).toService(ArduinoLocalizationContribution);
|
||||
bind(LocalizationBackendContribution).toSelf().inSingletonScope();
|
||||
rebind(TheiaLocalizationBackendContribution).toService(
|
||||
LocalizationBackendContribution
|
||||
);
|
||||
|
||||
// Survey notification bindings
|
||||
// It's currently unused. https://github.com/arduino/arduino-ide/pull/1150
|
||||
bind(SurveyNotificationServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SurveyNotificationService).toService(SurveyNotificationServiceImpl);
|
||||
bind(ConnectionHandler)
|
||||
.toDynamicValue(
|
||||
({ container }) =>
|
||||
new JsonRpcConnectionHandler(SurveyNotificationServicePath, () =>
|
||||
container.get<SurveyNotificationService>(SurveyNotificationService)
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
});
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import * as os from 'os';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
@@ -121,25 +122,39 @@ function toClangOptions(
|
||||
return { UseTab: 'Never', TabWidth: 2 };
|
||||
}
|
||||
|
||||
// See: https://releases.llvm.org/11.0.1/tools/clang/docs/ClangFormatStyleOptions.html
|
||||
export function style({ TabWidth, UseTab }: ClangFormatOptions): string {
|
||||
return JSON.stringify(styleJson({ TabWidth, UseTab })).replace(/\"/g, '\\"');
|
||||
let styleArgument = JSON.stringify(styleJson({ TabWidth, UseTab })).replace(
|
||||
/[\\"]/g,
|
||||
'\\$&'
|
||||
);
|
||||
if (os.platform() === 'win32') {
|
||||
// Windows command interpreter does not use backslash escapes. This causes the argument to have alternate quoted and
|
||||
// unquoted sections.
|
||||
// Special characters in the unquoted sections must be caret escaped.
|
||||
const styleArgumentSplit = styleArgument.split('"');
|
||||
for (let i = 1; i < styleArgumentSplit.length; i += 2) {
|
||||
styleArgumentSplit[i] = styleArgumentSplit[i].replace(/[<>^|]/g, '^$&');
|
||||
}
|
||||
|
||||
styleArgument = styleArgumentSplit.join('"');
|
||||
}
|
||||
|
||||
return styleArgument;
|
||||
}
|
||||
|
||||
function styleJson({
|
||||
TabWidth,
|
||||
UseTab,
|
||||
}: ClangFormatOptions): Record<string, unknown> {
|
||||
// Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration
|
||||
return {
|
||||
Language: 'Cpp',
|
||||
// # LLVM is the default style setting, used when a configuration option is not set here
|
||||
BasedOnStyle: 'LLVM',
|
||||
AccessModifierOffset: -2,
|
||||
AlignAfterOpenBracket: 'Align',
|
||||
AlignConsecutiveAssignments: false,
|
||||
AlignConsecutiveBitFields: false,
|
||||
AlignConsecutiveDeclarations: false,
|
||||
AlignConsecutiveMacros: false,
|
||||
AlignArrayOfStructures: 'None',
|
||||
AlignConsecutiveAssignments: 'None',
|
||||
AlignConsecutiveBitFields: 'None',
|
||||
AlignConsecutiveDeclarations: 'None',
|
||||
AlignConsecutiveMacros: 'None',
|
||||
AlignEscapedNewlines: 'DontAlign',
|
||||
AlignOperands: 'Align',
|
||||
AlignTrailingComments: true,
|
||||
@@ -150,16 +165,18 @@ function styleJson({
|
||||
AllowShortCaseLabelsOnASingleLine: true,
|
||||
AllowShortEnumsOnASingleLine: true,
|
||||
AllowShortFunctionsOnASingleLine: 'Empty',
|
||||
AllowShortIfStatementsOnASingleLine: 'Always',
|
||||
AllowShortIfStatementsOnASingleLine: 'AllIfsAndElse',
|
||||
AllowShortLambdasOnASingleLine: 'Empty',
|
||||
AllowShortLoopsOnASingleLine: true,
|
||||
AlwaysBreakAfterDefinitionReturnType: 'None',
|
||||
AlwaysBreakAfterReturnType: 'None',
|
||||
AlwaysBreakBeforeMultilineStrings: false,
|
||||
AlwaysBreakTemplateDeclarations: 'No',
|
||||
AttributeMacros: ['__capability'],
|
||||
BasedOnStyle: 'LLVM',
|
||||
BinPackArguments: true,
|
||||
BinPackParameters: true,
|
||||
// # Only used when "BreakBeforeBraces" set to "Custom"
|
||||
BitFieldColonSpacing: 'Both',
|
||||
BraceWrapping: {
|
||||
AfterCaseLabel: false,
|
||||
AfterClass: false,
|
||||
@@ -167,7 +184,7 @@ function styleJson({
|
||||
AfterEnum: false,
|
||||
AfterFunction: false,
|
||||
AfterNamespace: false,
|
||||
// #AfterObjCDeclaration:
|
||||
AfterObjCDeclaration: false,
|
||||
AfterStruct: false,
|
||||
AfterUnion: false,
|
||||
AfterExternBlock: false,
|
||||
@@ -176,104 +193,143 @@ function styleJson({
|
||||
BeforeLambdaBody: false,
|
||||
BeforeWhile: false,
|
||||
IndentBraces: false,
|
||||
SplitEmptyFunction: false,
|
||||
SplitEmptyRecord: false,
|
||||
SplitEmptyNamespace: false,
|
||||
SplitEmptyFunction: true,
|
||||
SplitEmptyRecord: true,
|
||||
SplitEmptyNamespace: true,
|
||||
},
|
||||
// # Java-specific
|
||||
// #BreakAfterJavaFieldAnnotations:
|
||||
BreakAfterJavaFieldAnnotations: false,
|
||||
BreakBeforeBinaryOperators: 'NonAssignment',
|
||||
BreakBeforeBraces: 'Attach',
|
||||
BreakBeforeConceptDeclarations: false,
|
||||
BreakBeforeInheritanceComma: false,
|
||||
BreakBeforeTernaryOperators: true,
|
||||
BreakConstructorInitializers: 'BeforeColon',
|
||||
BreakConstructorInitializersBeforeComma: false,
|
||||
BreakInheritanceList: 'BeforeColon',
|
||||
BreakStringLiterals: false,
|
||||
ColumnLimit: 0,
|
||||
// # "" matches none
|
||||
CommentPragmas: '',
|
||||
CompactNamespaces: false,
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true,
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false,
|
||||
ConstructorInitializerIndentWidth: 2,
|
||||
ContinuationIndentWidth: 2,
|
||||
Cpp11BracedListStyle: false,
|
||||
DeriveLineEnding: true,
|
||||
DerivePointerAlignment: true,
|
||||
DisableFormat: false,
|
||||
// # Docs say "Do not use this in config files". The default (LLVM 11.0.1) is "false".
|
||||
// #ExperimentalAutoDetectBinPacking:
|
||||
EmptyLineAfterAccessModifier: 'Leave',
|
||||
EmptyLineBeforeAccessModifier: 'Leave',
|
||||
ExperimentalAutoDetectBinPacking: false,
|
||||
FixNamespaceComments: false,
|
||||
ForEachMacros: [],
|
||||
ForEachMacros: ['foreach', 'Q_FOREACH', 'BOOST_FOREACH'],
|
||||
IfMacros: ['KJ_IF_MAYBE'],
|
||||
IncludeBlocks: 'Preserve',
|
||||
IncludeCategories: [],
|
||||
// # "" matches none
|
||||
IncludeCategories: [
|
||||
{
|
||||
Regex: '^"(llvm|llvm-c|clang|clang-c)/',
|
||||
Priority: 2,
|
||||
SortPriority: 0,
|
||||
CaseSensitive: false,
|
||||
},
|
||||
{
|
||||
Regex: '^(<|"(gtest|gmock|isl|json)/)',
|
||||
Priority: 3,
|
||||
SortPriority: 0,
|
||||
CaseSensitive: false,
|
||||
},
|
||||
{ Regex: '.*', Priority: 1, SortPriority: 0, CaseSensitive: false },
|
||||
],
|
||||
IncludeIsMainRegex: '',
|
||||
IncludeIsMainSourceRegex: '',
|
||||
IndentAccessModifiers: false,
|
||||
IndentCaseBlocks: true,
|
||||
IndentCaseLabels: true,
|
||||
IndentExternBlock: 'Indent',
|
||||
IndentGotoLabels: false,
|
||||
IndentPPDirectives: 'None',
|
||||
IndentRequires: true,
|
||||
IndentWidth: 2,
|
||||
IndentWrappedFunctionNames: false,
|
||||
InsertTrailingCommas: 'None',
|
||||
// # Java-specific
|
||||
// #JavaImportGroups:
|
||||
// # JavaScript-specific
|
||||
// #JavaScriptQuotes:
|
||||
// #JavaScriptWrapImports
|
||||
JavaScriptQuotes: 'Leave',
|
||||
JavaScriptWrapImports: true,
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true,
|
||||
LambdaBodyIndentation: 'Signature',
|
||||
Language: 'Cpp',
|
||||
MacroBlockBegin: '',
|
||||
MacroBlockEnd: '',
|
||||
// # Set to a large number to effectively disable
|
||||
MaxEmptyLinesToKeep: 100000,
|
||||
NamespaceIndentation: 'None',
|
||||
NamespaceMacros: [],
|
||||
// # Objective C-specific
|
||||
// #ObjCBinPackProtocolList:
|
||||
// #ObjCBlockIndentWidth:
|
||||
// #ObjCBreakBeforeNestedBlockParam:
|
||||
// #ObjCSpaceAfterProperty:
|
||||
// #ObjCSpaceBeforeProtocolList
|
||||
ObjCBinPackProtocolList: 'Auto',
|
||||
ObjCBlockIndentWidth: 2,
|
||||
ObjCBreakBeforeNestedBlockParam: true,
|
||||
ObjCSpaceAfterProperty: false,
|
||||
ObjCSpaceBeforeProtocolList: true,
|
||||
PPIndentWidth: -1,
|
||||
PackConstructorInitializers: 'BinPack',
|
||||
PenaltyBreakAssignment: 1,
|
||||
PenaltyBreakBeforeFirstCallParameter: 1,
|
||||
PenaltyBreakComment: 1,
|
||||
PenaltyBreakFirstLessLess: 1,
|
||||
PenaltyBreakOpenParenthesis: 1,
|
||||
PenaltyBreakString: 1,
|
||||
PenaltyBreakTemplateDeclaration: 1,
|
||||
PenaltyExcessCharacter: 1,
|
||||
PenaltyIndentedWhitespace: 1,
|
||||
PenaltyReturnTypeOnItsOwnLine: 1,
|
||||
// # Used as a fallback if alignment style can't be detected from code (DerivePointerAlignment: true)
|
||||
PointerAlignment: 'Right',
|
||||
RawStringFormats: [],
|
||||
QualifierAlignment: 'Leave',
|
||||
ReferenceAlignment: 'Pointer',
|
||||
ReflowComments: false,
|
||||
SortIncludes: false,
|
||||
RemoveBracesLLVM: false,
|
||||
SeparateDefinitionBlocks: 'Leave',
|
||||
ShortNamespaceLines: 0,
|
||||
SortIncludes: 'Never',
|
||||
SortJavaStaticImport: 'Before',
|
||||
SortUsingDeclarations: false,
|
||||
SpaceAfterCStyleCast: false,
|
||||
SpaceAfterLogicalNot: false,
|
||||
SpaceAfterTemplateKeyword: false,
|
||||
SpaceAroundPointerQualifiers: 'Default',
|
||||
SpaceBeforeAssignmentOperators: true,
|
||||
SpaceBeforeCaseColon: false,
|
||||
SpaceBeforeCpp11BracedList: false,
|
||||
SpaceBeforeCtorInitializerColon: true,
|
||||
SpaceBeforeInheritanceColon: true,
|
||||
SpaceBeforeParens: 'ControlStatements',
|
||||
SpaceBeforeParensOptions: {
|
||||
AfterControlStatements: true,
|
||||
AfterForeachMacros: true,
|
||||
AfterFunctionDefinitionName: false,
|
||||
AfterFunctionDeclarationName: false,
|
||||
AfterIfMacros: true,
|
||||
AfterOverloadedOperator: false,
|
||||
BeforeNonEmptyParentheses: false,
|
||||
},
|
||||
SpaceBeforeRangeBasedForLoopColon: true,
|
||||
SpaceBeforeSquareBrackets: false,
|
||||
SpaceInEmptyBlock: false,
|
||||
SpaceInEmptyParentheses: false,
|
||||
SpacesBeforeTrailingComments: 2,
|
||||
SpacesInAngles: false,
|
||||
SpacesInAngles: 'Leave',
|
||||
SpacesInCStyleCastParentheses: false,
|
||||
SpacesInConditionalStatement: false,
|
||||
SpacesInContainerLiterals: false,
|
||||
SpacesInLineCommentPrefix: { Minimum: 0, Maximum: -1 },
|
||||
SpacesInParentheses: false,
|
||||
SpacesInSquareBrackets: false,
|
||||
Standard: 'Auto',
|
||||
StatementMacros: [],
|
||||
StatementAttributeLikeMacros: ['Q_EMIT'],
|
||||
StatementMacros: ['Q_UNUSED', 'QT_REQUIRE_VERSION'],
|
||||
TabWidth,
|
||||
TypenameMacros: [],
|
||||
// # Default to LF if line endings can't be detected from the content (DeriveLineEnding).
|
||||
UseCRLF: false,
|
||||
UseTab,
|
||||
WhitespaceSensitiveMacros: [],
|
||||
WhitespaceSensitiveMacros: [
|
||||
'STRINGIZE',
|
||||
'PP_STRINGIZE',
|
||||
'BOOST_PP_STRINGIZE',
|
||||
'NS_SWIFT_NAME',
|
||||
'CF_SWIFT_NAME',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import {
|
||||
UploadUsingProgrammerResponse,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
||||
import { ResponseService } from '../common/protocol/response-service';
|
||||
import { Board, OutputMessage, Port, Status } from '../common/protocol';
|
||||
import { OutputMessage, Port, Status } from '../common/protocol';
|
||||
import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
|
||||
import { Port as GrpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
|
||||
import { ApplicationError, CommandService, Disposable, nls } from '@theia/core';
|
||||
@@ -33,6 +33,12 @@ import { tryParseError } from './cli-error-parser';
|
||||
import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
||||
import { firstToUpperCase, notEmpty } from '../common/utils';
|
||||
import { ServiceError } from './service-error';
|
||||
import { ExecuteWithProgress, ProgressResponse } from './grpc-progressible';
|
||||
|
||||
namespace Uploadable {
|
||||
export type Request = UploadRequest | UploadUsingProgrammerRequest;
|
||||
export type Response = UploadResponse | UploadUsingProgrammerResponse;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
@@ -45,27 +51,27 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
@inject(CommandService)
|
||||
private readonly commandService: CommandService;
|
||||
|
||||
async compile(
|
||||
options: CoreService.Compile.Options & {
|
||||
exportBinaries?: boolean;
|
||||
compilerWarnings?: CompilerWarnings;
|
||||
}
|
||||
): Promise<void> {
|
||||
async compile(options: CoreService.Options.Compile): Promise<void> {
|
||||
const coreClient = await this.coreClient;
|
||||
const { client, instance } = coreClient;
|
||||
let buildPath: string | undefined = undefined;
|
||||
const handler = this.createOnDataHandler<CompileResponse>((response) => {
|
||||
const progressHandler = this.createProgressHandler(options);
|
||||
const buildPathHandler = (response: CompileResponse) => {
|
||||
const currentBuildPath = response.getBuildPath();
|
||||
if (!buildPath && currentBuildPath) {
|
||||
if (currentBuildPath) {
|
||||
buildPath = currentBuildPath;
|
||||
} else {
|
||||
if (!!currentBuildPath && currentBuildPath !== buildPath) {
|
||||
if (!!buildPath && currentBuildPath !== buildPath) {
|
||||
throw new Error(
|
||||
`The CLI has already provided a build path: <${buildPath}>, and there is a new build path value: <${currentBuildPath}>.`
|
||||
`The CLI has already provided a build path: <${buildPath}>, and IDE2 received a new build path value: <${currentBuildPath}>.`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const handler = this.createOnDataHandler<CompileResponse>(
|
||||
progressHandler,
|
||||
buildPathHandler
|
||||
);
|
||||
const request = this.compileRequest(options, instance);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
client
|
||||
@@ -132,20 +138,20 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
}
|
||||
|
||||
private compileRequest(
|
||||
options: CoreService.Compile.Options & {
|
||||
options: CoreService.Options.Compile & {
|
||||
exportBinaries?: boolean;
|
||||
compilerWarnings?: CompilerWarnings;
|
||||
},
|
||||
instance: Instance
|
||||
): CompileRequest {
|
||||
const { sketch, board, compilerWarnings } = options;
|
||||
const { sketch, fqbn, compilerWarnings } = options;
|
||||
const sketchUri = sketch.uri;
|
||||
const sketchPath = FileUri.fsPath(sketchUri);
|
||||
const request = new CompileRequest();
|
||||
request.setInstance(instance);
|
||||
request.setSketchPath(sketchPath);
|
||||
if (board?.fqbn) {
|
||||
request.setFqbn(board.fqbn);
|
||||
if (fqbn) {
|
||||
request.setFqbn(fqbn);
|
||||
}
|
||||
if (compilerWarnings) {
|
||||
request.setWarnings(compilerWarnings.toLowerCase());
|
||||
@@ -163,56 +169,44 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
return request;
|
||||
}
|
||||
|
||||
upload(options: CoreService.Upload.Options): Promise<void> {
|
||||
upload(options: CoreService.Options.Upload): Promise<void> {
|
||||
const { usingProgrammer } = options;
|
||||
return this.doUpload(
|
||||
options,
|
||||
() => new UploadRequest(),
|
||||
(client, req) => client.upload(req),
|
||||
(message: string, locations: CoreError.ErrorLocation[]) =>
|
||||
CoreError.UploadFailed(message, locations),
|
||||
'upload'
|
||||
usingProgrammer
|
||||
? new UploadUsingProgrammerRequest()
|
||||
: new UploadRequest(),
|
||||
(client) =>
|
||||
(usingProgrammer ? client.uploadUsingProgrammer : client.upload).bind(
|
||||
client
|
||||
),
|
||||
usingProgrammer
|
||||
? CoreError.UploadUsingProgrammerFailed
|
||||
: CoreError.UploadFailed,
|
||||
`upload${usingProgrammer ? ' using programmer' : ''}`
|
||||
);
|
||||
}
|
||||
|
||||
async uploadUsingProgrammer(
|
||||
options: CoreService.Upload.Options
|
||||
): Promise<void> {
|
||||
return this.doUpload(
|
||||
options,
|
||||
() => new UploadUsingProgrammerRequest(),
|
||||
(client, req) => client.uploadUsingProgrammer(req),
|
||||
(message: string, locations: CoreError.ErrorLocation[]) =>
|
||||
CoreError.UploadUsingProgrammerFailed(message, locations),
|
||||
'upload using programmer'
|
||||
);
|
||||
}
|
||||
|
||||
protected async doUpload(
|
||||
options: CoreService.Upload.Options,
|
||||
requestFactory: () => UploadRequest | UploadUsingProgrammerRequest,
|
||||
responseHandler: (
|
||||
client: ArduinoCoreServiceClient,
|
||||
request: UploadRequest | UploadUsingProgrammerRequest
|
||||
) => ClientReadableStream<UploadResponse | UploadUsingProgrammerResponse>,
|
||||
errorHandler: (
|
||||
message: string,
|
||||
locations: CoreError.ErrorLocation[]
|
||||
) => ApplicationError<number, CoreError.ErrorLocation[]>,
|
||||
protected async doUpload<
|
||||
REQ extends Uploadable.Request,
|
||||
RESP extends Uploadable.Response
|
||||
>(
|
||||
options: CoreService.Options.Upload,
|
||||
request: REQ,
|
||||
responseFactory: (
|
||||
client: ArduinoCoreServiceClient
|
||||
) => (request: REQ) => ClientReadableStream<RESP>,
|
||||
errorCtor: ApplicationError.Constructor<number, CoreError.ErrorLocation[]>,
|
||||
task: string
|
||||
): Promise<void> {
|
||||
await this.compile(Object.assign(options, { exportBinaries: false }));
|
||||
|
||||
const coreClient = await this.coreClient;
|
||||
const { client, instance } = coreClient;
|
||||
const request = this.uploadOrUploadUsingProgrammerRequest(
|
||||
options,
|
||||
instance,
|
||||
requestFactory
|
||||
);
|
||||
const handler = this.createOnDataHandler();
|
||||
const progressHandler = this.createProgressHandler(options);
|
||||
const handler = this.createOnDataHandler(progressHandler);
|
||||
const grpcCall = responseFactory(client);
|
||||
return this.notifyUploadWillStart(options).then(() =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
responseHandler(client, request)
|
||||
grpcCall(this.initUploadRequest(request, options, instance))
|
||||
.on('data', handler.onData)
|
||||
.on('error', (error) => {
|
||||
if (!ServiceError.is(error)) {
|
||||
@@ -227,7 +221,7 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
);
|
||||
this.sendResponse(error.details, OutputMessage.Severity.Error);
|
||||
reject(
|
||||
errorHandler(
|
||||
errorCtor(
|
||||
message,
|
||||
tryParseError({
|
||||
content: handler.stderr,
|
||||
@@ -245,18 +239,17 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
);
|
||||
}
|
||||
|
||||
private uploadOrUploadUsingProgrammerRequest(
|
||||
options: CoreService.Upload.Options,
|
||||
instance: Instance,
|
||||
requestFactory: () => UploadRequest | UploadUsingProgrammerRequest
|
||||
): UploadRequest | UploadUsingProgrammerRequest {
|
||||
const { sketch, board, port, programmer } = options;
|
||||
private initUploadRequest<REQ extends Uploadable.Request>(
|
||||
request: REQ,
|
||||
options: CoreService.Options.Upload,
|
||||
instance: Instance
|
||||
): REQ {
|
||||
const { sketch, fqbn, port, programmer } = options;
|
||||
const sketchPath = FileUri.fsPath(sketch.uri);
|
||||
const request = requestFactory();
|
||||
request.setInstance(instance);
|
||||
request.setSketchPath(sketchPath);
|
||||
if (board?.fqbn) {
|
||||
request.setFqbn(board.fqbn);
|
||||
if (fqbn) {
|
||||
request.setFqbn(fqbn);
|
||||
}
|
||||
request.setPort(this.createPort(port));
|
||||
if (programmer) {
|
||||
@@ -271,10 +264,11 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
return request;
|
||||
}
|
||||
|
||||
async burnBootloader(options: CoreService.Bootloader.Options): Promise<void> {
|
||||
async burnBootloader(options: CoreService.Options.Bootloader): Promise<void> {
|
||||
const coreClient = await this.coreClient;
|
||||
const { client, instance } = coreClient;
|
||||
const handler = this.createOnDataHandler();
|
||||
const progressHandler = this.createProgressHandler(options);
|
||||
const handler = this.createOnDataHandler(progressHandler);
|
||||
const request = this.burnBootloaderRequest(options, instance);
|
||||
return this.notifyUploadWillStart(options).then(() =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
@@ -311,14 +305,14 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
}
|
||||
|
||||
private burnBootloaderRequest(
|
||||
options: CoreService.Bootloader.Options,
|
||||
options: CoreService.Options.Bootloader,
|
||||
instance: Instance
|
||||
): BurnBootloaderRequest {
|
||||
const { board, port, programmer } = options;
|
||||
const { fqbn, port, programmer } = options;
|
||||
const request = new BurnBootloaderRequest();
|
||||
request.setInstance(instance);
|
||||
if (board?.fqbn) {
|
||||
request.setFqbn(board.fqbn);
|
||||
if (fqbn) {
|
||||
request.setFqbn(fqbn);
|
||||
}
|
||||
request.setPort(this.createPort(port));
|
||||
if (programmer) {
|
||||
@@ -329,8 +323,24 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
return request;
|
||||
}
|
||||
|
||||
private createProgressHandler<R extends ProgressResponse>(
|
||||
options: CoreService.Options.Base
|
||||
): (response: R) => void {
|
||||
// If client did not provide the progress ID, do nothing.
|
||||
if (!options.progressId) {
|
||||
return () => {
|
||||
/* NOOP */
|
||||
};
|
||||
}
|
||||
return ExecuteWithProgress.createDataCallback<R>({
|
||||
progressId: options.progressId,
|
||||
responseService: this.responseService,
|
||||
});
|
||||
}
|
||||
|
||||
private createOnDataHandler<R extends StreamingResponse>(
|
||||
onResponse?: (response: R) => void
|
||||
// TODO: why not creating a composite handler with progress, `build_path`, and out/err stream handlers?
|
||||
...handlers: ((response: R) => void)[]
|
||||
): Disposable & {
|
||||
stderr: Buffer[];
|
||||
onData: (response: R) => void;
|
||||
@@ -343,14 +353,14 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
}
|
||||
});
|
||||
});
|
||||
const onData = StreamingResponse.createOnDataHandler(
|
||||
const onData = StreamingResponse.createOnDataHandler({
|
||||
stderr,
|
||||
(out, err) => {
|
||||
onData: (out, err) => {
|
||||
buffer.addChunk(out);
|
||||
buffer.addChunk(err, OutputMessage.Severity.Error);
|
||||
},
|
||||
onResponse
|
||||
);
|
||||
handlers,
|
||||
});
|
||||
return {
|
||||
dispose: () => buffer.dispose(),
|
||||
stderr,
|
||||
@@ -366,28 +376,28 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||
}
|
||||
|
||||
private async notifyUploadWillStart({
|
||||
board,
|
||||
fqbn,
|
||||
port,
|
||||
}: {
|
||||
board?: Board | undefined;
|
||||
fqbn?: string | undefined;
|
||||
port?: Port | undefined;
|
||||
}): Promise<void> {
|
||||
return this.monitorManager.notifyUploadStarted(board, port);
|
||||
return this.monitorManager.notifyUploadStarted(fqbn, port);
|
||||
}
|
||||
|
||||
private async notifyUploadDidFinish({
|
||||
board,
|
||||
fqbn,
|
||||
port,
|
||||
}: {
|
||||
board?: Board | undefined;
|
||||
fqbn?: string | undefined;
|
||||
port?: Port | undefined;
|
||||
}): Promise<Status> {
|
||||
return this.monitorManager.notifyUploadFinished(board, port);
|
||||
return this.monitorManager.notifyUploadFinished(fqbn, port);
|
||||
}
|
||||
|
||||
private mergeSourceOverrides(
|
||||
req: { getSourceOverrideMap(): jspb.Map<string, string> },
|
||||
options: CoreService.Compile.Options
|
||||
options: CoreService.Options.Compile
|
||||
): void {
|
||||
const sketchPath = FileUri.fsPath(options.sketch.uri);
|
||||
for (const uri of Object.keys(options.sourceOverride)) {
|
||||
@@ -418,18 +428,24 @@ type StreamingResponse =
|
||||
namespace StreamingResponse {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function createOnDataHandler<R extends StreamingResponse>(
|
||||
stderr: Uint8Array[],
|
||||
onData: (out: Uint8Array, err: Uint8Array) => void,
|
||||
onResponse?: (response: R) => void
|
||||
options: StreamingResponse.Options<R>
|
||||
): (response: R) => void {
|
||||
return (response: R) => {
|
||||
const out = response.getOutStream_asU8();
|
||||
const err = response.getErrStream_asU8();
|
||||
stderr.push(err);
|
||||
onData(out, err);
|
||||
if (onResponse) {
|
||||
onResponse(response);
|
||||
}
|
||||
options.stderr.push(err);
|
||||
options.onData(out, err);
|
||||
options.handlers?.forEach((handler) => handler(response));
|
||||
};
|
||||
}
|
||||
export interface Options<R extends StreamingResponse> {
|
||||
readonly stderr: Uint8Array[];
|
||||
readonly onData: (out: Uint8Array, err: Uint8Array) => void;
|
||||
/**
|
||||
* Additional request handlers.
|
||||
* For example, when tracing the progress of a task and
|
||||
* collecting the output (out, err) and the `build_path` from the CLI.
|
||||
*/
|
||||
readonly handlers?: ((response: R) => void)[];
|
||||
}
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ import {
|
||||
DownloadProgress,
|
||||
TaskProgress,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
||||
import { CompileResponse } from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
||||
import {
|
||||
PlatformInstallResponse,
|
||||
PlatformUninstallResponse,
|
||||
@@ -21,6 +22,11 @@ import {
|
||||
LibraryUninstallResponse,
|
||||
ZipLibraryInstallResponse,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/lib_pb';
|
||||
import {
|
||||
BurnBootloaderResponse,
|
||||
UploadResponse,
|
||||
UploadUsingProgrammerResponse,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
|
||||
|
||||
type LibraryProgressResponse =
|
||||
| LibraryInstallResponse
|
||||
@@ -78,15 +84,62 @@ namespace IndexProgressResponse {
|
||||
return { download: response.getDownloadProgress() };
|
||||
}
|
||||
}
|
||||
/**
|
||||
* These responses have neither `task` nor `progress` property but for the sake of completeness
|
||||
* on typings (from the gRPC API) and UX, these responses represent an indefinite progress.
|
||||
*/
|
||||
type IndefiniteProgressResponse =
|
||||
| UploadResponse
|
||||
| UploadUsingProgrammerResponse
|
||||
| BurnBootloaderResponse;
|
||||
namespace IndefiniteProgressResponse {
|
||||
export function is(
|
||||
response: unknown
|
||||
): response is IndefiniteProgressResponse {
|
||||
return (
|
||||
response instanceof UploadResponse ||
|
||||
response instanceof UploadUsingProgrammerResponse ||
|
||||
response instanceof BurnBootloaderResponse
|
||||
);
|
||||
}
|
||||
}
|
||||
type DefiniteProgressResponse = CompileResponse;
|
||||
namespace DefiniteProgressResponse {
|
||||
export function is(response: unknown): response is DefiniteProgressResponse {
|
||||
return response instanceof CompileResponse;
|
||||
}
|
||||
}
|
||||
type CoreProgressResponse =
|
||||
| DefiniteProgressResponse
|
||||
| IndefiniteProgressResponse;
|
||||
namespace CoreProgressResponse {
|
||||
export function is(response: unknown): response is CoreProgressResponse {
|
||||
return (
|
||||
DefiniteProgressResponse.is(response) ||
|
||||
IndefiniteProgressResponse.is(response)
|
||||
);
|
||||
}
|
||||
export function workUnit(response: CoreProgressResponse): UnitOfWork {
|
||||
if (DefiniteProgressResponse.is(response)) {
|
||||
return { task: response.getProgress() };
|
||||
}
|
||||
return UnitOfWork.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
export type ProgressResponse =
|
||||
| LibraryProgressResponse
|
||||
| PlatformProgressResponse
|
||||
| IndexProgressResponse;
|
||||
| IndexProgressResponse
|
||||
| CoreProgressResponse;
|
||||
|
||||
interface UnitOfWork {
|
||||
task?: TaskProgress;
|
||||
download?: DownloadProgress;
|
||||
}
|
||||
namespace UnitOfWork {
|
||||
export const Unknown: UnitOfWork = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* It's solely a dev thing. Flip it to `true` if you want to debug the progress from the CLI responses.
|
||||
@@ -115,14 +168,28 @@ export namespace ExecuteWithProgress {
|
||||
console.log(`Progress response [${uuid}]: ${json}`);
|
||||
}
|
||||
}
|
||||
const { task, download } = resolve(response);
|
||||
const unitOfWork = resolve(response);
|
||||
const { task, download } = unitOfWork;
|
||||
if (!download && !task) {
|
||||
console.warn(
|
||||
"Implementation error. Neither 'download' nor 'task' is available."
|
||||
);
|
||||
// This is still an API error from the CLI, but IDE2 ignores it.
|
||||
// Technically, it does not cause an error, but could mess up the progress reporting.
|
||||
// See an example of an empty object `{}` repose here: https://github.com/arduino/arduino-ide/issues/906#issuecomment-1171145630.
|
||||
// report a fake unknown progress.
|
||||
if (unitOfWork === UnitOfWork.Unknown && progressId) {
|
||||
if (progressId) {
|
||||
responseService.reportProgress?.({
|
||||
progressId,
|
||||
message: '',
|
||||
work: { done: Number.NaN, total: Number.NaN },
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
// This is still an API error from the CLI, but IDE2 ignores it.
|
||||
// Technically, it does not cause an error, but could mess up the progress reporting.
|
||||
// See an example of an empty object `{}` repose here: https://github.com/arduino/arduino-ide/issues/906#issuecomment-1171145630.
|
||||
console.warn(
|
||||
"Implementation error. Neither 'download' nor 'task' is available."
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (task && download) {
|
||||
@@ -132,6 +199,7 @@ export namespace ExecuteWithProgress {
|
||||
}
|
||||
if (task) {
|
||||
const message = task.getName() || task.getMessage();
|
||||
const percent = task.getPercent();
|
||||
if (message) {
|
||||
if (progressId) {
|
||||
responseService.reportProgress?.({
|
||||
@@ -141,6 +209,14 @@ export namespace ExecuteWithProgress {
|
||||
});
|
||||
}
|
||||
responseService.appendToOutput?.({ chunk: `${message}\n` });
|
||||
} else if (percent) {
|
||||
if (progressId) {
|
||||
responseService.reportProgress?.({
|
||||
progressId,
|
||||
message,
|
||||
work: { done: percent, total: 100 },
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (download) {
|
||||
if (download.getFile() && !localFile) {
|
||||
@@ -191,38 +267,38 @@ export namespace ExecuteWithProgress {
|
||||
return PlatformProgressResponse.workUnit(response);
|
||||
} else if (IndexProgressResponse.is(response)) {
|
||||
return IndexProgressResponse.workUnit(response);
|
||||
} else if (CoreProgressResponse.is(response)) {
|
||||
return CoreProgressResponse.workUnit(response);
|
||||
}
|
||||
console.warn('Unhandled gRPC response', response);
|
||||
return {};
|
||||
}
|
||||
function toJson(response: ProgressResponse): string | undefined {
|
||||
let object: Record<string, unknown> | undefined = undefined;
|
||||
if (response instanceof LibraryInstallResponse) {
|
||||
return JSON.stringify(LibraryInstallResponse.toObject(false, response));
|
||||
object = LibraryInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof LibraryUninstallResponse) {
|
||||
return JSON.stringify(LibraryUninstallResponse.toObject(false, response));
|
||||
object = LibraryUninstallResponse.toObject(false, response);
|
||||
} else if (response instanceof ZipLibraryInstallResponse) {
|
||||
return JSON.stringify(
|
||||
ZipLibraryInstallResponse.toObject(false, response)
|
||||
);
|
||||
object = ZipLibraryInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof PlatformInstallResponse) {
|
||||
return JSON.stringify(PlatformInstallResponse.toObject(false, response));
|
||||
object = PlatformInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof PlatformUninstallResponse) {
|
||||
return JSON.stringify(
|
||||
PlatformUninstallResponse.toObject(false, response)
|
||||
);
|
||||
object = PlatformUninstallResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateIndexResponse) {
|
||||
return JSON.stringify(UpdateIndexResponse.toObject(false, response));
|
||||
object = UpdateIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateLibrariesIndexResponse) {
|
||||
return JSON.stringify(
|
||||
UpdateLibrariesIndexResponse.toObject(false, response)
|
||||
);
|
||||
object = UpdateLibrariesIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateCoreLibrariesIndexResponse) {
|
||||
return JSON.stringify(
|
||||
UpdateCoreLibrariesIndexResponse.toObject(false, response)
|
||||
);
|
||||
object = UpdateCoreLibrariesIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof CompileResponse) {
|
||||
object = CompileResponse.toObject(false, response);
|
||||
}
|
||||
console.warn('Unhandled gRPC response', response);
|
||||
return undefined;
|
||||
if (!object) {
|
||||
console.warn('Unhandled gRPC response', response);
|
||||
return undefined;
|
||||
}
|
||||
return JSON.stringify(object);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,142 +11,142 @@ export class ArduinoLocalizationContribution
|
||||
async registerLocalizations(registry: LocalizationRegistry): Promise<void> {
|
||||
registry.registerLocalizationFromRequire(
|
||||
'af',
|
||||
require('../../build/i18n/af.json')
|
||||
require('../../../build/i18n/af.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'en',
|
||||
require('../../build/i18n/en.json')
|
||||
require('../../../build/i18n/en.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'fr',
|
||||
require('../../build/i18n/fr.json')
|
||||
require('../../../build/i18n/fr.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ko',
|
||||
require('../../build/i18n/ko.json')
|
||||
require('../../../build/i18n/ko.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'pt-br',
|
||||
require('../../build/i18n/pt.json')
|
||||
require('../../../build/i18n/pt.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'uk_UA',
|
||||
require('../../build/i18n/uk_UA.json')
|
||||
require('../../../build/i18n/uk_UA.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ar',
|
||||
require('../../build/i18n/ar.json')
|
||||
require('../../../build/i18n/ar.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'es',
|
||||
require('../../build/i18n/es.json')
|
||||
require('../../../build/i18n/es.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'he',
|
||||
require('../../build/i18n/he.json')
|
||||
require('../../../build/i18n/he.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'my_MM',
|
||||
require('../../build/i18n/my_MM.json')
|
||||
require('../../../build/i18n/my_MM.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ro',
|
||||
require('../../build/i18n/ro.json')
|
||||
require('../../../build/i18n/ro.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'zh-cn',
|
||||
require('../../build/i18n/zh.json')
|
||||
require('../../../build/i18n/zh.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'bg',
|
||||
require('../../build/i18n/bg.json')
|
||||
require('../../../build/i18n/bg.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'eu',
|
||||
require('../../build/i18n/eu.json')
|
||||
require('../../../build/i18n/eu.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'hu',
|
||||
require('../../build/i18n/hu.json')
|
||||
require('../../../build/i18n/hu.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ne',
|
||||
require('../../build/i18n/ne.json')
|
||||
require('../../../build/i18n/ne.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ru',
|
||||
require('../../build/i18n/ru.json')
|
||||
require('../../../build/i18n/ru.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'zh_TW',
|
||||
require('../../build/i18n/zh_TW.json')
|
||||
require('../../../build/i18n/zh_TW.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'de',
|
||||
require('../../build/i18n/de.json')
|
||||
require('../../../build/i18n/de.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'fa',
|
||||
require('../../build/i18n/fa.json')
|
||||
require('../../../build/i18n/fa.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'it',
|
||||
require('../../build/i18n/it.json')
|
||||
require('../../../build/i18n/it.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'nl',
|
||||
require('../../build/i18n/nl.json')
|
||||
require('../../../build/i18n/nl.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'sv_SE',
|
||||
require('../../build/i18n/sv_SE.json')
|
||||
require('../../../build/i18n/sv_SE.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'el',
|
||||
require('../../build/i18n/el.json')
|
||||
require('../../../build/i18n/el.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'fil',
|
||||
require('../../build/i18n/fil.json')
|
||||
require('../../../build/i18n/fil.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'ja',
|
||||
require('../../build/i18n/ja.json')
|
||||
require('../../../build/i18n/ja.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'pl',
|
||||
require('../../build/i18n/pl.json')
|
||||
require('../../../build/i18n/pl.json')
|
||||
);
|
||||
|
||||
registry.registerLocalizationFromRequire(
|
||||
'tr',
|
||||
require('../../build/i18n/tr.json')
|
||||
require('../../../build/i18n/tr.json')
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
import * as express from 'express';
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { LocalizationBackendContribution as TheiaLocalizationBackendContribution } from '@theia/core/lib/node/i18n/localization-backend-contribution';
|
||||
import { PluginDeployer } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
||||
import { PluginDeployerImpl } from '@theia/plugin-ext/lib/main/node/plugin-deployer-impl';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
|
||||
@injectable()
|
||||
export class LocalizationBackendContribution extends TheiaLocalizationBackendContribution {
|
||||
@inject(PluginDeployer)
|
||||
private readonly pluginDeployer: PluginDeployerImpl;
|
||||
|
||||
private readonly initialized = new Deferred<void>();
|
||||
|
||||
override async initialize(): Promise<void> {
|
||||
this.pluginDeployer.onDidDeploy(() => {
|
||||
this.initialized.resolve();
|
||||
});
|
||||
return super.initialize();
|
||||
}
|
||||
|
||||
override configure(app: express.Application): void {
|
||||
app.get('/i18n/:locale', async (req, res) => {
|
||||
let locale = req.params.locale;
|
||||
/*
|
||||
Waiting for the deploy of the language plugins is neecessary to avoid checking the available
|
||||
languages before they're finished to be loaded: https://github.com/eclipse-theia/theia/issues/11471
|
||||
*/
|
||||
const start = performance.now();
|
||||
await this.initialized.promise;
|
||||
console.info(
|
||||
'Waiting for the deploy of the language plugins took: ' +
|
||||
(performance.now() - start) +
|
||||
' ms.'
|
||||
);
|
||||
locale = this.localizationProvider
|
||||
.getAvailableLanguages()
|
||||
.some((e) => e.languageId === locale)
|
||||
? locale
|
||||
: 'en';
|
||||
this.localizationProvider.setCurrentLanguage(locale);
|
||||
res.send(this.localizationProvider.loadLocalization(locale));
|
||||
});
|
||||
}
|
||||
}
|
@@ -58,7 +58,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
* combination specified, false in all other cases.
|
||||
*/
|
||||
isStarted(board: Board, port: Port): boolean {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
if (monitor) {
|
||||
return monitor.isStarted();
|
||||
@@ -106,7 +106,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
port: Port,
|
||||
connectToClient: (status: Status) => void
|
||||
): Promise<void> {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
|
||||
let monitor = this.monitorServices.get(monitorID);
|
||||
if (!monitor) {
|
||||
@@ -138,7 +138,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
* @param port port monitored
|
||||
*/
|
||||
async stopMonitor(board: Board, port: Port): Promise<void> {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
if (!monitor) {
|
||||
// There's no monitor to stop, bail
|
||||
@@ -155,7 +155,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
* @returns port of the MonitorService's WebSocket
|
||||
*/
|
||||
getWebsocketAddressPort(board: Board, port: Port): number {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
if (!monitor) {
|
||||
return -1;
|
||||
@@ -168,17 +168,17 @@ export class MonitorManager extends CoreClientAware {
|
||||
* that an upload process started on that exact board/port combination.
|
||||
* This must be done so that we can stop the monitor for the time being
|
||||
* until the upload process finished.
|
||||
* @param board board connected to port
|
||||
* @param fqbn the FQBN of the board connected to port
|
||||
* @param port port to monitor
|
||||
*/
|
||||
async notifyUploadStarted(board?: Board, port?: Port): Promise<void> {
|
||||
if (!board || !port) {
|
||||
async notifyUploadStarted(fqbn?: string, port?: Port): Promise<void> {
|
||||
if (!fqbn || !port) {
|
||||
// We have no way of knowing which monitor
|
||||
// to retrieve if we don't have this information.
|
||||
return;
|
||||
}
|
||||
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(fqbn, port);
|
||||
this.addToMonitorIDsByUploadState('uploadInProgress', monitorID);
|
||||
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
@@ -194,19 +194,22 @@ export class MonitorManager extends CoreClientAware {
|
||||
/**
|
||||
* Notifies the monitor service of that board/port combination
|
||||
* that an upload process started on that exact board/port combination.
|
||||
* @param board board connected to port
|
||||
* @param fqbn the FQBN of the board connected to port
|
||||
* @param port port to monitor
|
||||
* @returns a Status object to know if the process has been
|
||||
* started or if there have been errors.
|
||||
*/
|
||||
async notifyUploadFinished(board?: Board, port?: Port): Promise<Status> {
|
||||
async notifyUploadFinished(
|
||||
fqbn?: string | undefined,
|
||||
port?: Port
|
||||
): Promise<Status> {
|
||||
let status: Status = Status.NOT_CONNECTED;
|
||||
let portDidChangeOnUpload = false;
|
||||
|
||||
// We have no way of knowing which monitor
|
||||
// to retrieve if we don't have this information.
|
||||
if (board && port) {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
if (fqbn && port) {
|
||||
const monitorID = this.monitorID(fqbn, port);
|
||||
this.removeFromMonitorIDsByUploadState('uploadInProgress', monitorID);
|
||||
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
@@ -277,7 +280,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
port: Port,
|
||||
settings: PluggableMonitorSettings
|
||||
) {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
let monitor = this.monitorServices.get(monitorID);
|
||||
if (!monitor) {
|
||||
monitor = this.createMonitor(board, port);
|
||||
@@ -296,7 +299,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
board: Board,
|
||||
port: Port
|
||||
): Promise<MonitorSettings> {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
const monitor = this.monitorServices.get(monitorID);
|
||||
if (!monitor) {
|
||||
return {};
|
||||
@@ -312,7 +315,7 @@ export class MonitorManager extends CoreClientAware {
|
||||
* @returns a new instance of MonitorService ready to use.
|
||||
*/
|
||||
private createMonitor(board: Board, port: Port): MonitorService {
|
||||
const monitorID = this.monitorID(board, port);
|
||||
const monitorID = this.monitorID(board.fqbn, port);
|
||||
const monitor = this.monitorServiceFactory({
|
||||
board,
|
||||
port,
|
||||
@@ -341,12 +344,12 @@ export class MonitorManager extends CoreClientAware {
|
||||
|
||||
/**
|
||||
* Utility function to create a unique ID for a monitor service.
|
||||
* @param board
|
||||
* @param fqbn
|
||||
* @param port
|
||||
* @returns a unique monitor ID
|
||||
*/
|
||||
private monitorID(board: Board, port: Port): MonitorID {
|
||||
const splitFqbn = board?.fqbn?.split(':') || [];
|
||||
private monitorID(fqbn: string | undefined, port: Port): MonitorID {
|
||||
const splitFqbn = fqbn?.split(':') || [];
|
||||
const shortenedFqbn = splitFqbn.slice(0, 3).join(':') || '';
|
||||
return `${shortenedFqbn}-${port.address}-${port.protocol}`;
|
||||
}
|
||||
|
@@ -341,15 +341,7 @@ export class SketchesServiceImpl
|
||||
|
||||
async cloneExample(uri: string): Promise<Sketch> {
|
||||
const sketch = await this.loadSketch(uri);
|
||||
const parentPath = await new Promise<string>((resolve, reject) => {
|
||||
temp.mkdir({ prefix }, (err, dirPath) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(dirPath);
|
||||
});
|
||||
});
|
||||
const parentPath = await this.createTempFolder();
|
||||
const destinationUri = FileUri.create(
|
||||
path.join(parentPath, sketch.name)
|
||||
).toString();
|
||||
@@ -373,21 +365,7 @@ export class SketchesServiceImpl
|
||||
'dec',
|
||||
];
|
||||
const today = new Date();
|
||||
const parentPath = await new Promise<string>((resolve, reject) => {
|
||||
temp.mkdir({ prefix }, (createError, dirPath) => {
|
||||
if (createError) {
|
||||
reject(createError);
|
||||
return;
|
||||
}
|
||||
fs.realpath.native(dirPath, (resolveError, resolvedDirPath) => {
|
||||
if (resolveError) {
|
||||
reject(resolveError);
|
||||
return;
|
||||
}
|
||||
resolve(resolvedDirPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
const parentPath = await this.createTempFolder();
|
||||
const sketchBaseName = `sketch_${
|
||||
monthNames[today.getMonth()]
|
||||
}${today.getDate()}`;
|
||||
@@ -438,6 +416,30 @@ void loop() {
|
||||
return this.loadSketch(FileUri.create(sketchDir).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temp folder and returns with a promise that resolves with the canonicalized absolute pathname of the newly created temp folder.
|
||||
* This method ensures that the file-system path pointing to the new temp directory is fully resolved.
|
||||
* For example, on Windows, instead of getting an [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename), callers will get a fully resolved path.
|
||||
* `C:\\Users\\KITTAA~1\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a` will be `C:\\Users\\kittaakos\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a`
|
||||
*/
|
||||
private createTempFolder(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
temp.mkdir({ prefix }, (createError, dirPath) => {
|
||||
if (createError) {
|
||||
reject(createError);
|
||||
return;
|
||||
}
|
||||
fs.realpath.native(dirPath, (resolveError, resolvedDirPath) => {
|
||||
if (resolveError) {
|
||||
reject(resolveError);
|
||||
return;
|
||||
}
|
||||
resolve(resolvedDirPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getSketchFolder(uri: string): Promise<Sketch | undefined> {
|
||||
if (!uri) {
|
||||
return undefined;
|
||||
@@ -534,15 +536,7 @@ void loop() {
|
||||
// `ncp` makes a recursion and copies the folders over and over again. In such cases, we copy the source into a temp folder,
|
||||
// then move it to the desired destination.
|
||||
const destination = FileUri.fsPath(destinationUri);
|
||||
let tempDestination = await new Promise<string>((resolve, reject) => {
|
||||
temp.track().mkdir({ prefix }, async (err, dirPath) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(dirPath);
|
||||
});
|
||||
});
|
||||
let tempDestination = await this.createTempFolder();
|
||||
tempDestination = path.join(tempDestination, sketch.name);
|
||||
await fs.promises.mkdir(tempDestination, { recursive: true });
|
||||
await copy(source, tempDestination);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "browser-app",
|
||||
"version": "2.0.0-rc9",
|
||||
"version": "2.0.0-rc9.2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@theia/core": "1.25.0",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@theia/process": "1.25.0",
|
||||
"@theia/terminal": "1.25.0",
|
||||
"@theia/workspace": "1.25.0",
|
||||
"arduino-ide-extension": "2.0.0-rc9"
|
||||
"arduino-ide-extension": "2.0.0-rc9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "1.25.0"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "electron-app",
|
||||
"version": "2.0.0-rc9",
|
||||
"version": "2.0.0-rc9.2",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "src-gen/frontend/electron-main.js",
|
||||
"dependencies": {
|
||||
@@ -21,7 +21,7 @@
|
||||
"@theia/process": "1.25.0",
|
||||
"@theia/terminal": "1.25.0",
|
||||
"@theia/workspace": "1.25.0",
|
||||
"arduino-ide-extension": "2.0.0-rc9"
|
||||
"arduino-ide-extension": "2.0.0-rc9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/cli": "1.25.0",
|
||||
@@ -61,7 +61,7 @@
|
||||
},
|
||||
"generator": {
|
||||
"config": {
|
||||
"preloadTemplate": "<div class='theia-preload' style='background-color: rgb(237, 241, 242);'></div>"
|
||||
"preloadTemplate": "./resources/preload.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
electron-app/patch/frontend/index.js
Normal file
100
electron-app/patch/frontend/index.js
Normal file
@@ -0,0 +1,100 @@
|
||||
// Patch for the startup theme. Customizes the `ThemeService.get().defaultTheme();` to dispatch the default IDE2 theme based on the OS' theme.
|
||||
// For all subsequent starts of the IDE the theme applied will be the last one set by the user.
|
||||
|
||||
// With the current version of Theia adopted (1.25) it is not possible to extend the `ThemeService`, it will be possible starting from Theia 1.27.
|
||||
// Once the version of Theia is updated, this patch will be removed and this functionality will be implemented via dependency injection.
|
||||
// Ideally, we should open a PR in Theia and add support for `light` and `dark` default themes in the app config.
|
||||
|
||||
const {
|
||||
ThemeService,
|
||||
ThemeServiceSymbol,
|
||||
BuiltinThemeProvider,
|
||||
} = require('@theia/core/lib/browser/theming');
|
||||
const {
|
||||
ApplicationProps,
|
||||
} = require('@theia/application-package/lib/application-props');
|
||||
const {
|
||||
FrontendApplicationConfigProvider,
|
||||
} = require('@theia/core/lib/browser/frontend-application-config-provider');
|
||||
|
||||
// It is a mighty hack to support theme updates in the bundled IDE2.
|
||||
// If the custom theme registration happens before the restoration of the existing monaco themes, then any custom theme changes will be ignored.
|
||||
// This patch introduces a static deferred promise in the monaco-theming service that will be resolved when the restoration is ready.
|
||||
// IDE2 cannot require the monaco theme service on the outer module level, as it requires the application config provider to be initialized,
|
||||
// but the initialization happens only in the generated `index.js`.
|
||||
// This patch customizes the monaco theme service behavior before loading the DI containers via the preload.
|
||||
// The preload is called only once before the app loads. The Theia extensions are not loaded at that point, but the app config provider is ready.
|
||||
const preloader = require('@theia/core/lib/browser/preloader');
|
||||
const originalPreload = preloader.preload;
|
||||
preloader.preload = async function () {
|
||||
const { MonacoThemingService } = require('@theia/monaco/lib/browser/monaco-theming-service');
|
||||
const { MonacoThemeServiceIsReady } = require('arduino-ide-extension/lib/browser/utils/window');
|
||||
const { Deferred } = require('@theia/core/lib/common/promise-util');
|
||||
const ready = new Deferred();
|
||||
if (!window[MonacoThemeServiceIsReady]) {
|
||||
window[MonacoThemeServiceIsReady] = ready;
|
||||
console.log('Registered a custom monaco-theme service initialization signal on the window object.');
|
||||
}
|
||||
// Here, it is safe to patch the theme service, app config provider is ready.
|
||||
MonacoThemingService.init = async function () {
|
||||
this.updateBodyUiTheme();
|
||||
ThemeService.get().onDidColorThemeChange(() => this.updateBodyUiTheme());
|
||||
await this.restore();
|
||||
ready.resolve();
|
||||
}.bind(MonacoThemingService);
|
||||
return originalPreload();
|
||||
}.bind(preloader);
|
||||
|
||||
const lightTheme = 'arduino-theme';
|
||||
const darkTheme = 'arduino-theme-dark';
|
||||
const defaultTheme =
|
||||
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? darkTheme
|
||||
: lightTheme;
|
||||
|
||||
const originalGet = FrontendApplicationConfigProvider.get;
|
||||
FrontendApplicationConfigProvider.get = function () {
|
||||
const originalProps = originalGet.bind(FrontendApplicationConfigProvider)();
|
||||
return { ...originalProps, defaultTheme };
|
||||
}.bind(FrontendApplicationConfigProvider);
|
||||
|
||||
const arduinoDarkTheme = {
|
||||
id: 'arduino-theme-dark',
|
||||
type: 'dark',
|
||||
label: 'Dark (Arduino)',
|
||||
editorTheme: 'arduino-theme-dark',
|
||||
activate() {},
|
||||
deactivate() {},
|
||||
};
|
||||
|
||||
const arduinoLightTheme = {
|
||||
id: 'arduino-theme',
|
||||
type: 'light',
|
||||
label: 'Light (Arduino)',
|
||||
editorTheme: 'arduino-theme',
|
||||
activate() {},
|
||||
deactivate() {},
|
||||
};
|
||||
|
||||
if (!window[ThemeServiceSymbol]) {
|
||||
const themeService = new ThemeService();
|
||||
Object.defineProperty(themeService, 'defaultTheme', {
|
||||
get: function () {
|
||||
return (
|
||||
this.themes[defaultTheme] ||
|
||||
this.themes[ApplicationProps.DEFAULT.frontend.config.defaultTheme]
|
||||
);
|
||||
},
|
||||
});
|
||||
themeService.register(
|
||||
...BuiltinThemeProvider.themes,
|
||||
arduinoDarkTheme,
|
||||
arduinoLightTheme
|
||||
);
|
||||
themeService.startupTheme();
|
||||
themeService.setCurrentTheme(defaultTheme);
|
||||
window[ThemeServiceSymbol] = themeService;
|
||||
}
|
||||
|
||||
// Require the original, generated `index.js` for `webpack` as the next entry for the `bundle.js`.
|
||||
require('../../src-gen/frontend/index');
|
114
electron-app/resources/preload.html
Normal file
114
electron-app/resources/preload.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<head>
|
||||
<style>
|
||||
/* The colors are hard-coded and based on the `editor.background` and `editor.foreground` values from `./arduino-ide-extension/src/browser/data/default.color-theme.json` */
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
/* The colors are hard-coded and based on the `editor.background` and `editor.foreground` values from `./arduino-ide-extension/src/browser/data/dark.color-theme.json` */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
background: #1f272a;
|
||||
}
|
||||
}
|
||||
|
||||
.theia-preload {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
/* Above styles copied from https://github.com/eclipse-theia/theia/blob/5aeef6c0c683b4e91713ab736957e6655b486adc/packages/core/src/browser/style/index.css#L147-L161 */
|
||||
/* Otherwise, there is a flickering when Theia's CSS loads. */
|
||||
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.theia-preload::after {
|
||||
/* remove default loading animation */
|
||||
content: none;
|
||||
}
|
||||
|
||||
.spinner-container {
|
||||
display: flex;
|
||||
flex-direction: center;
|
||||
align-self: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.custom-spinner {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.custom-spinner svg {
|
||||
width: 16vw;
|
||||
height: 16vh;
|
||||
animation-delay: 0;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: preload-spinner;
|
||||
animation-timing-function: ease;
|
||||
}
|
||||
|
||||
@keyframes preload-spinner {
|
||||
0% {
|
||||
transform: scale(1.0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='spinner-container'>
|
||||
<div class='custom-spinner'>
|
||||
<svg id="spinner" xmlns="http://www.w3.org/2000/svg" width="2499" height="2500"
|
||||
viewBox="0 0 1372.201 1372.684">
|
||||
<path fill="#00979D" stroke="#81C9CB" stroke-width=".932" stroke-miterlimit="10"
|
||||
d="M1371.701 686.024c0 378.658-306.972 685.605-685.549 685.605C307.451 1371.629.5 1064.682.5 686.024.5 307.455 307.451.483 686.152.483c378.594.001 685.549 306.972 685.549 685.541z" />
|
||||
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="-16.3" y1="16.071" x2="1354.901" y2="16.071"
|
||||
gradientTransform="matrix(1 0 0 -1 16.8 702.696)">
|
||||
<stop offset=".117" stop-color="#fff" stop-opacity="0" />
|
||||
<stop offset=".252" stop-color="#c0d1d3" stop-opacity=".153" />
|
||||
<stop offset=".387" stop-color="#91b3b7" stop-opacity=".306" />
|
||||
<stop offset=".52" stop-color="#6d9fa3" stop-opacity=".457" />
|
||||
<stop offset=".65" stop-color="#4d9195" stop-opacity=".604" />
|
||||
<stop offset=".776" stop-color="#30888b" stop-opacity=".746" />
|
||||
<stop offset=".895" stop-color="#148386" stop-opacity=".881" />
|
||||
<stop offset="1" stop-color="#008184" />
|
||||
</linearGradient>
|
||||
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="-16.8" y1="16.071" x2="1355.401" y2="16.071"
|
||||
gradientTransform="matrix(1 0 0 -1 16.8 702.696)">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity="0" />
|
||||
<stop offset=".153" stop-color="#c0d1d3" stop-opacity=".153" />
|
||||
<stop offset=".306" stop-color="#91b3b7" stop-opacity=".306" />
|
||||
<stop offset=".457" stop-color="#6d9fa3" stop-opacity=".457" />
|
||||
<stop offset=".604" stop-color="#4d9195" stop-opacity=".604" />
|
||||
<stop offset=".746" stop-color="#30888b" stop-opacity=".746" />
|
||||
<stop offset=".881" stop-color="#148386" stop-opacity=".881" />
|
||||
<stop offset="1" stop-color="#008184" />
|
||||
</linearGradient>
|
||||
<path opacity=".5" fill="url(#a)" stroke="url(#b)" stroke-miterlimit="10"
|
||||
d="M1371.701 686.595c0 378.65-306.972 685.606-685.549 685.606C307.451 1372.201.5 1065.23.5 686.595.5 308.019 307.451 1.048 686.152 1.048c378.594.016 685.549 306.97 685.549 685.547z" />
|
||||
<g fill="#FFF">
|
||||
<path
|
||||
d="M947.959 931.196c-12.909 0-26.127-.929-39.127-2.864-108.978-15.554-181.848-93.822-222.665-153.989-40.946 60.166-113.811 138.512-222.74 154.045a275.864 275.864 0 0 1-39.133 2.785c-67.753 0-131.358-25.217-179.201-71.003-48.299-46.165-74.951-108.114-74.951-174.171 0-66.14 26.651-128.004 75.021-174.253 47.797-45.793 111.449-70.936 179.231-70.936 12.918 0 26.067.928 39.023 2.783 108.932 15.535 181.794 93.813 222.743 153.99 40.825-60.177 113.689-138.432 222.658-153.99 13-1.863 26.148-2.783 39.066-2.783 67.753 0 131.401 25.208 179.197 70.936 48.345 46.249 74.937 108.113 74.937 174.253 0 66.057-26.524 128.006-74.868 174.171-47.881 45.785-111.434 71.026-179.191 71.026M734.42 686.024c21.283 40.534 84.067 141.676 186.692 156.375 8.984 1.236 18.028 1.923 26.839 1.923 92.185 0 167.225-71.002 167.225-158.322s-75.023-158.321-167.291-158.321c-8.812 0-17.853.629-26.753 1.921-102.644 14.664-165.428 115.806-186.712 156.424M424.393 527.702c-92.308 0-167.36 70.998-167.36 158.321 0 87.305 75.021 158.322 167.245 158.322 8.852 0 17.897-.688 26.879-1.922 102.629-14.697 165.394-115.783 186.689-156.375-21.237-40.535-84.061-141.761-186.689-156.376-8.877-1.341-17.945-1.97-26.764-1.97" />
|
||||
<path
|
||||
d="M354.37 662.051h152.625v49.181H354.37zM1016.484 662.051h-51.671v-51.747h-49.348v51.747h-51.648v49.181h51.648v51.737h49.348v-51.737h51.671z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
@@ -17,4 +17,10 @@ config.module.rules.push({
|
||||
loader: require.resolve('@theia/application-manager/lib/expose-loader')
|
||||
}); */
|
||||
|
||||
|
||||
// Load the patched `index.js` that sets the desired theme in IDE2 based on the OS' theme.
|
||||
// The `patch/frontend/index.js` will require the original, generated `index.js`.
|
||||
// See: https://github.com/arduino/arduino-ide/pull/1160.
|
||||
config.entry.bundle = require('path').resolve(__dirname, 'patch/frontend/index.js');
|
||||
|
||||
module.exports = config;
|
6
electron/.gitignore
vendored
6
electron/.gitignore
vendored
@@ -15,4 +15,8 @@ dist/
|
||||
electron-builder.env
|
||||
|
||||
# The generated `package.json` under the `build` folder.
|
||||
build/package.json
|
||||
build/package.json
|
||||
|
||||
# Resources the packager copies from dev to prod
|
||||
build/resources/preload.html
|
||||
build/patch/frontend/index.js
|
||||
|
@@ -1,4 +1,18 @@
|
||||
// @ts-check
|
||||
|
||||
// Patch for on Linux when `XDG_CONFIG_HOME` is not available, `node-log-rotate` creates the folder with `undefined` name.
|
||||
// See https://github.com/lemon-sour/node-log-rotate/issues/23 and https://github.com/arduino/arduino-ide/issues/394.
|
||||
// If the IDE2 is running on Linux, and the `XDG_CONFIG_HOME` variable is not available, set it to avoid the `undefined` folder.
|
||||
// From the specs: https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html
|
||||
// "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used."
|
||||
const os = require('os');
|
||||
if (os.platform() === 'linux' && !process.env['XDG_CONFIG_HOME']) {
|
||||
const { join } = require('path');
|
||||
const home = process.env['HOME'];
|
||||
const xdgConfigHome = home ? join(home, '.config') : join(os.homedir(), '.config');
|
||||
process.env['XDG_CONFIG_HOME'] = xdgConfigHome;
|
||||
}
|
||||
|
||||
const { setup, log } = require('node-log-rotate');
|
||||
setup({
|
||||
appName: 'Arduino IDE',
|
||||
|
@@ -1,59 +0,0 @@
|
||||
// Patch for the startup theme. Customizes the `ThemeService.get().defaultTheme();` to dispatch the default IDE2 theme based on the OS' theme.
|
||||
// For all subsequent starts of the IDE the theme applied will be the last one set by the user.
|
||||
|
||||
// With the current version of Theia adopted (1.25) it is not possible to extend the `ThemeService`, it will be possible starting from Theia 1.27.
|
||||
// Once the version of Theia is updated, this patch will be removed and this functionality will be implemented via dependency injection.
|
||||
// Ideally, we should open a PR in Theia and add support for `light` and `dark` default themes in the app config.
|
||||
|
||||
const {
|
||||
ThemeService,
|
||||
ThemeServiceSymbol,
|
||||
BuiltinThemeProvider,
|
||||
} = require('@theia/core/lib/browser/theming');
|
||||
const {
|
||||
ApplicationProps,
|
||||
} = require('@theia/application-package/lib/application-props');
|
||||
|
||||
const lightTheme = 'arduino-theme';
|
||||
const darkTheme = 'arduino-theme-dark';
|
||||
const defaultTheme =
|
||||
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? darkTheme
|
||||
: lightTheme;
|
||||
|
||||
const arduinoDarkTheme = {
|
||||
id: 'arduino-theme-dark',
|
||||
type: 'dark',
|
||||
label: 'Dark (Arduino)',
|
||||
editorTheme: 'arduino-theme-dark',
|
||||
activate() { },
|
||||
deactivate() { }
|
||||
};
|
||||
|
||||
const arduinoLightTheme = {
|
||||
id: 'arduino-theme',
|
||||
type: 'light',
|
||||
label: 'Light (Arduino)',
|
||||
editorTheme: 'arduino-theme',
|
||||
activate() { },
|
||||
deactivate() { }
|
||||
};
|
||||
|
||||
if (!window[ThemeServiceSymbol]) {
|
||||
const themeService = new ThemeService();
|
||||
Object.defineProperty(themeService, 'defaultTheme', {
|
||||
get: function () {
|
||||
return (
|
||||
this.themes[defaultTheme] ||
|
||||
this.themes[ApplicationProps.DEFAULT.frontend.config.defaultTheme]
|
||||
);
|
||||
},
|
||||
});
|
||||
themeService.register(...BuiltinThemeProvider.themes, arduinoDarkTheme, arduinoLightTheme);
|
||||
themeService.startupTheme();
|
||||
themeService.setCurrentTheme(defaultTheme);
|
||||
window[ThemeServiceSymbol] = themeService;
|
||||
}
|
||||
|
||||
// Require the original, generated `index.js` for `webpack` as the next entry for the `bundle.js`.
|
||||
require('../../src-gen/frontend/index');
|
@@ -141,7 +141,7 @@
|
||||
"theiaPluginsDir": "plugins",
|
||||
"theiaPlugins": {
|
||||
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.4.vsix",
|
||||
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.5.vsix",
|
||||
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
|
||||
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",
|
||||
"cortex-debug": "https://open-vsx.org/api/marus25/cortex-debug/0.3.10/file/marus25.cortex-debug-0.3.10.vsix",
|
||||
|
@@ -7,6 +7,8 @@
|
||||
const glob = require('glob');
|
||||
const isCI = require('is-ci');
|
||||
shell.env.THEIA_ELECTRON_SKIP_REPLACE_FFMPEG = '1'; // Do not run the ffmpeg validation for the packager.
|
||||
// Note, this will crash on PI if the available memory is less than desired heap size.
|
||||
// https://github.com/shelljs/shelljs/issues/1024#issuecomment-1001552543
|
||||
shell.env.NODE_OPTIONS = '--max_old_space_size=4096'; // Increase heap size for the CI
|
||||
shell.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = 'true'; // Skip download and avoid `ERROR: Failed to download Chromium`.
|
||||
const template = require('./config').generateTemplate(
|
||||
@@ -14,7 +16,7 @@
|
||||
);
|
||||
const utils = require('./utils');
|
||||
const merge = require('deepmerge');
|
||||
const { isRelease, isElectronPublish, getChannelFile } = utils;
|
||||
const { isRelease, getChannelFile } = utils;
|
||||
const { version } = template;
|
||||
const { productName } = template.build;
|
||||
|
||||
@@ -58,6 +60,11 @@
|
||||
.filter((filename) => resourcesToKeep.indexOf(filename) === -1)
|
||||
.forEach((filename) => rm('-rf', path('..', 'build', filename)));
|
||||
|
||||
// Clean up the `./electron/build/patch` and `./electron/build/resources` folder with Git.
|
||||
// To avoid file duplication between bundled app and dev mode, some files are copied from `./electron-app` to `./electron/build` folder.
|
||||
const foldersToSyncFromDev = ['patch', 'resources'];
|
||||
foldersToSyncFromDev.forEach(filename => shell.exec(`git -C ${path('..', 'build', filename)} clean -ffxdq`, { async: false }));
|
||||
|
||||
const extensions = require('./extensions.json');
|
||||
echo(
|
||||
`Building the application with the following extensions:\n${extensions
|
||||
@@ -70,20 +77,28 @@
|
||||
// Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. |
|
||||
//----------------------------------------------------------------------------------------------+
|
||||
mkdir('-p', path('..', workingCopy));
|
||||
for (const name of [
|
||||
for (const filename of [
|
||||
...allDependencies,
|
||||
'yarn.lock',
|
||||
'package.json',
|
||||
'lerna.json',
|
||||
'i18n'
|
||||
]) {
|
||||
cp('-rf', path(rootPath, name), path('..', workingCopy));
|
||||
cp('-rf', path(rootPath, filename), path('..', workingCopy));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------+
|
||||
// Copy the patched `index.js` for the frontend, the Theia preload, etc. from `./electron-app` |
|
||||
//---------------------------------------------------------------------------------------------+
|
||||
for (const filename of foldersToSyncFromDev) {
|
||||
cp('-rf', path('..', workingCopy, 'electron-app', filename), path('..', 'build'));
|
||||
}
|
||||
|
||||
//----------------------------------------------+
|
||||
// Sanity check: all versions must be the same. |
|
||||
//----------------------------------------------+
|
||||
verifyVersions(allDependencies);
|
||||
|
||||
//----------------------------------------------------------------------+
|
||||
// Use the nightly patch version if not a release but requires publish. |
|
||||
//----------------------------------------------------------------------+
|
||||
@@ -438,6 +453,12 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('fs').PathLike} file
|
||||
* @param {string|undefined} [algorithm="sha512"]
|
||||
* @param {BufferEncoding|undefined} [encoding="base64"]
|
||||
* @param {object|undefined} [options]
|
||||
*/
|
||||
async function hashFile(
|
||||
file,
|
||||
algorithm = 'sha512',
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Visit Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Close and Install",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Aflaai",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.",
|
||||
"cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.",
|
||||
"cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "saamstel",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
|
||||
"invalid.theme": "Invalid theme.",
|
||||
"language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "Netwerk",
|
||||
"newSketchbookLocation": "Select new sketchbook location",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Beide NL & CR",
|
||||
"noLineEndings": "No Line Ending",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Tydstempel",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "زيارة Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "قم بالاغلاق و التحديث",
|
||||
"closeToInstallNotice": "اغلق البرمجية و حّدث الجهاز الخاص بك ",
|
||||
"downloadButton": "حمّل",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True اذا كان يجب تحذير المستخدمين قبل سحب مشروع من السحابة . True افتراضيا",
|
||||
"cloud.push.warn": "True اذا كان يجب تحذير المستخدمين قبل دفع مشروع الى السحابة . True افتراضيا",
|
||||
"cloud.pushpublic.warn": "True اذا كان يجب تحذير المستخدمين قبل دفع مشروع عام الى السحابة . True افتراضيا",
|
||||
"cloud.sketchSyncEnpoint": "الوجهة المستخدمة لدفع و سحب المشاريع من الخلفية . تشير افتراضيا الى Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "الوجهة المستخدمة لدفع و سحب المشاريع من الخلفية . تشير افتراضيا الى Arduino Cloud API.",
|
||||
"compile": "الترجمة",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "موقع ملف المشروع غير صالح : {0}",
|
||||
"invalid.theme": "سمة غير صالحة",
|
||||
"language.log": "\"True\" اذا كان مخدم اللغات الخاص بArduino يستطيع توليد سجلات الى ملف المشروع , و الا \"False\", و هي كذلك بشكل افتراضي.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "اعدادات الوكيل يدوياً",
|
||||
"network": "شبكة",
|
||||
"newSketchbookLocation": "اختر مكان المشروع الجديد",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": " NL & CR معاً",
|
||||
"noLineEndings": "نهاية السطر غير موجودة",
|
||||
"notConnected": "غير متصل . اختر لوحة و منفذ للاتصال تلقائيا",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "الطابع الزمني",
|
||||
"toggleTimestamp": "تبديل الطابع الزمني"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Ardunio cc-yi Ziyarət Edin"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Bağla Və Yüklə",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.",
|
||||
"cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.",
|
||||
"cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "compile",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
|
||||
"invalid.theme": "Invalid theme.",
|
||||
"language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "Network",
|
||||
"newSketchbookLocation": "Select new sketchbook location",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Both NL & CR",
|
||||
"noLineEndings": "No Line Ending",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Timestamp",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Посетете Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Close and Install",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True е, ако потребителите трябва да бъдат предупредени, преди да се изтегли скица от облака. По подразбиране е true.",
|
||||
"cloud.push.warn": "True, ако потребителите трябва да бъдат предупредени, преди да бъде пусната скица в облака. По подразбиране е true.",
|
||||
"cloud.pushpublic.warn": "True, ако потребителите трябва да бъдат предупредени, преди да бъде изпратена публична скица в облака. По подразбиране е true.",
|
||||
"cloud.sketchSyncEnpoint": "Крайната точка, използвана за изпращане и изтегляне на скици от бекенда. По подразбиране той сочи към Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "Крайната точка, използвана за изпращане и изтегляне на скици от бекенда. По подразбиране той сочи към Arduino Cloud API.",
|
||||
"compile": "компилиране",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Невалидно местоположение на скицника: {0}",
|
||||
"invalid.theme": "Невалидна тема.",
|
||||
"language.log": "True, ако езиковият сървър на Arduino трябва да генерира лог файлове в папката за скици. В противен случай false. По подразбиране е false.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Ръчна конфигурация на прокси",
|
||||
"network": "Мрежа",
|
||||
"newSketchbookLocation": "Изберете местоположение за новата скицниката",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Както NL, така и CR",
|
||||
"noLineEndings": "Без край на реда",
|
||||
"notConnected": "Няма връзка. Изберете платка и порт за автоматично свързване.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Печат за време",
|
||||
"toggleTimestamp": "Превключване на клеймото за време"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Visiteu Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Tanca i instal·la",
|
||||
"closeToInstallNotice": "Tanqueu el programari i instal·leu l'actualització a la vostra màquina.",
|
||||
"downloadButton": "Descarregar",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "És cert si s'ha d'avisar als usuaris abans de baixar un programa del núvol. El valor predeterminat és true.",
|
||||
"cloud.push.warn": "És cert si s'ha d'avisar als usuaris abans d'enviar un programa del núvol. El valor predeterminat és true.",
|
||||
"cloud.pushpublic.warn": "És cert si s'ha d'avisar als usuaris abans d'enviar un programa públic al núvol. El valor predeterminat és true.",
|
||||
"cloud.sketchSyncEnpoint": "El punt final s'utilitza per a enviar i descarregar programes des d'un backend. Per defecte apunta a l'API d'Arduino Cloud.",
|
||||
"cloud.sketchSyncEndpoint": "El punt final s'utilitza per a enviar i descarregar programes des d'un backend. Per defecte apunta a l'API d'Arduino Cloud.",
|
||||
"compile": "compilar",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "La ubicació del quadern de programes no és vàlida: {0}",
|
||||
"invalid.theme": "Tema no vàlid.",
|
||||
"language.log": "És cert si el servidor d'idiomes Arduino hauria de generar fitxers de registre a la carpeta de programes. En cas contrari, fals. És fals per defecte.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Configuració manual del proxy",
|
||||
"network": "Xarxa",
|
||||
"newSketchbookLocation": "Seleccioneu una ubicació nova del quadern de programes",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Ambdós NL & CR",
|
||||
"noLineEndings": "Sense final de línia",
|
||||
"notConnected": "No connectat. Seleccioneu una tarja i un port per connectar-vos automàticament.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Marca de temps",
|
||||
"toggleTimestamp": "Activa o desactiva la marca de temps"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Navštívit Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Zavřít a nainstalovat",
|
||||
"closeToInstallNotice": "Vypněte program a nainstalujte update na Váš stroj. ",
|
||||
"downloadButton": "Stáhnout",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "Ano pokud by měl být uživatel varován před stahováním cloud sketche. Ano je výchozí hodnota. ",
|
||||
"cloud.push.warn": "Ano pokud by měl být uživatel varován před odesláním cloud sketche. Ano je výchozí hodnota. ",
|
||||
"cloud.pushpublic.warn": "Ano pokud by měl být uživatel varován před odesláním veřejné sketche do cloudu. Ano je výchozí hodnota. ",
|
||||
"cloud.sketchSyncEnpoint": "Endpoint použitý pro stahování a odesílání sketchí z backendu. Ve výchozím stavu je toto směrováno na Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "Endpoint použitý pro stahování a odesílání sketchí z backendu. Ve výchozím stavu je toto směrováno na Arduino Cloud API.",
|
||||
"compile": "kompilovat",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Neplatné umístění projektů:{0}",
|
||||
"invalid.theme": "Neplatné téma.",
|
||||
"language.log": "Ano pokud by jazykový server pro Arduino měl generovat logovací soubory do složky se sketchi, jinak ne. Ne je výchozí hodnota.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Ruční nastavení proxy",
|
||||
"network": "Síť",
|
||||
"newSketchbookLocation": "Zvolit nové umístění projektů",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Oba NL & CR",
|
||||
"noLineEndings": "Bez konce řádku",
|
||||
"notConnected": "Nepřipojen. Zvolte desku a port pro automatické připojení.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Časová značka",
|
||||
"toggleTimestamp": "Přepnout časovou značku"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Besuche Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Schließen und Installieren",
|
||||
"closeToInstallNotice": "Schließe die Software und installiere das Update auf deinem Computer",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "Wahr, wenn Benutzer vor dem Herunterladen eines Sketches aus der Cloud gewarnt werden sollen. Standardmäßig Wahr.",
|
||||
"cloud.push.warn": "Wahr, wenn Benutzer vor dem Hochladen eines Cloud-Sketches gewarnt werden sollen. Standardmäßig Wahr.",
|
||||
"cloud.pushpublic.warn": "Wahr, wenn Benutzer vor dem Hochladen eines öffentlichen Sketches in die Cloud gewarnt werden sollen. Standardmäßig Wahr.",
|
||||
"cloud.sketchSyncEnpoint": "Der Endpunkt, um Sketches zu/von einem Backend zu laden. Standardeinstellung ist die Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "Der Endpunkt, um Sketches zu/von einem Backend zu laden. Standardeinstellung ist die Arduino Cloud API.",
|
||||
"compile": "Kompilieren",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Ungültiger Sketchbook Speicherort: {0}",
|
||||
"invalid.theme": "Ungültiges Erscheinungsbild",
|
||||
"language.log": "Wahr, wenn der Arduino Language Server Logfiles in den Sketch-Ordner schreiben soll. Sonst falsch. Standardeinstellung ist falsch.\n ",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manuelle Proxy Einstellung",
|
||||
"network": "Netzwerk",
|
||||
"newSketchbookLocation": "Wähle einen neuen Ort für das Sketchbook ",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Sowohl NL als auch CR",
|
||||
"noLineEndings": "Kein Zeilenende",
|
||||
"notConnected": "Nicht verbunden. Wählen Sie ein Board und einen Port, um automatisch zu verbinden.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Zeitstempel",
|
||||
"toggleTimestamp": "Zeitstempel an/aus"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Επίσκεψη Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Close and Install",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "Αληθές αν οι χρήστες πρέπει προειδοποιηθούν πριν τραβηχτεί ενα σχέδιο σύννεφου. Προεπιλογή ως αληθές.",
|
||||
"cloud.push.warn": "Αληθές αν οι χρήστες πρέπει προειδοποιηθούν πριν σπρωχθεί ενα σχέδιο σύννεφου. Προεπιλογή ως αληθές. ",
|
||||
"cloud.pushpublic.warn": "Αληθές αν οι χρήστες πρέπει προειδοποιηθούν πριν σπρωχθεί ενα δημόσιο σχέδιο σύννεφου. Προεπιλογή ως αληθές. ",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "μεταγλώττιση",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Μη-έγκυρη τοποθεσία σχεδίων: {0}",
|
||||
"invalid.theme": "Μη-έγκυρο θέμα.",
|
||||
"language.log": "Αληθές αν ο Arduino Language Server πρέπει να παράξει αρχεία κατάστασης στον φάκελο σχεδίου. Διαφορετικά, ψευδές. Είναι ψευδές απο προεπιλογή.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "Δίκτυο",
|
||||
"newSketchbookLocation": "Επιλογή νέας τοποθεσίας σχεδίων",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Both NL & CR",
|
||||
"noLineEndings": "No Line Ending",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Timestamp",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
@@ -36,6 +36,7 @@
|
||||
"boardsManager": "Boards Manager",
|
||||
"bootloader": {
|
||||
"burnBootloader": "Burn Bootloader",
|
||||
"burningBootloader": "Burning bootloader...",
|
||||
"doneBurningBootloader": "Done burning bootloader."
|
||||
},
|
||||
"burnBootloader": {
|
||||
@@ -306,6 +307,7 @@
|
||||
"archiveSketch": "Archive Sketch",
|
||||
"cantOpen": "A folder named \"{0}\" already exists. Can't open sketch.",
|
||||
"close": "Are you sure you want to close the sketch?",
|
||||
"compile": "Compiling sketch...",
|
||||
"configureAndUpload": "Configure And Upload",
|
||||
"createdArchive": "Created archive '{0}'.",
|
||||
"doneCompiling": "Done compiling.",
|
||||
@@ -327,6 +329,7 @@
|
||||
"titleSketchbook": "Sketchbook",
|
||||
"upload": "Upload",
|
||||
"uploadUsingProgrammer": "Upload Using Programmer",
|
||||
"uploading": "Uploading...",
|
||||
"userFieldsNotFoundError": "Can't find user fields for connected board",
|
||||
"verify": "Verify",
|
||||
"verifyOrCompile": "Verify/Compile"
|
||||
|
37
i18n/es.json
37
i18n/es.json
@@ -11,7 +11,7 @@
|
||||
"configDialog2": "Si seleccionas solo una placa podrás compilar, pero no cargar tu sketch.",
|
||||
"configDialogTitle": "Seleccione otra placa y puerto",
|
||||
"couldNotFindPreviouslySelected": "No se ha podido encontrar la placa previamente seleccionada '{0}' en la plataforma instalada '{1}'. Por favor, vuelve a seleccionar manualmente la placa que quieres utilizar. ¿Quieres volver a seleccionarla ahora?",
|
||||
"disconnected": "Disconnected",
|
||||
"disconnected": "Desconectado",
|
||||
"getBoardInfo": "Obtener información de la placa",
|
||||
"inSketchbook": " (en el Sketchbook)",
|
||||
"installManually": "Instalar manualmente",
|
||||
@@ -23,7 +23,7 @@
|
||||
"platformMissing": "La plataforma seleccionada para la placa '{0}' no está instalada.",
|
||||
"pleasePickBoard": "Por favor, elija una placa conectada al puerto que haya seleccionado.",
|
||||
"port": "Puerto {0}",
|
||||
"portLabel": "Port: {0}",
|
||||
"portLabel": "Puerto: {0}",
|
||||
"programmer": "Programador",
|
||||
"reselectLater": "Vuelve a seleccionar más tarde",
|
||||
"selectBoard": "Seleccionar Placa",
|
||||
@@ -59,11 +59,11 @@
|
||||
"uploadingCertificates": "Cargando certificados."
|
||||
},
|
||||
"cli-error-parser": {
|
||||
"keyboardError": "'Keyboard' not found. Does your sketch include the line '#include <Keyboard.h>'?",
|
||||
"mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?"
|
||||
"keyboardError": "'Keyboard' no encontrado. ¿Tiene tu proyecto incluida la linea '#include <Keyboard.h>'?",
|
||||
"mouseError": "'Mouse' no encontrado. ¿Tiene tu proyecto incluida la linea '#include <Mouse.h>'?"
|
||||
},
|
||||
"cloud": {
|
||||
"account": "Account",
|
||||
"account": "Cuenta",
|
||||
"chooseSketchVisibility": "Elige la visibilidad de tu Sketch:",
|
||||
"connected": "Conectado",
|
||||
"continue": "Continuar",
|
||||
@@ -88,14 +88,14 @@
|
||||
"pushSketch": "Pulsa para listar las URLs de la tarjetas no oficiales",
|
||||
"pushSketchMsg": "Este es un Sketch público. Antes de enviarlo, asegúrate de que cualquier información sensible está definida en los archivos arduino_secrets.h. Puedes hacer que un Sketch sea privado desde el panel Compartir.",
|
||||
"remote": "Remoto",
|
||||
"remoteSketchbook": "Remote Sketchbook",
|
||||
"remoteSketchbook": "Libreria de proyectos remota",
|
||||
"share": "Compartir...",
|
||||
"shareSketch": "Compartir Sketch",
|
||||
"showHideRemoveSketchbook": "Mostrar/Ocultar Sketchbook Remoto",
|
||||
"signIn": "Iniciar sesión",
|
||||
"signInToCloud": "Iniciar sesión en Arduino Cloud",
|
||||
"signOut": "Cerrar sesión",
|
||||
"sync": "Sync",
|
||||
"sync": "Sincronizar",
|
||||
"syncEditSketches": "Sincroniza y edita tus Arduino Cloud Sketches",
|
||||
"visitArduinoCloud": "Visita Arduino Cloud para crear Cloud Sketches. "
|
||||
},
|
||||
@@ -129,12 +129,12 @@
|
||||
"replaceTitle": "Reemplazar"
|
||||
},
|
||||
"coreContribution": {
|
||||
"copyError": "Copy error messages"
|
||||
"copyError": "Copiar mensajes de error"
|
||||
},
|
||||
"daemon": {
|
||||
"restart": "Restart Daemon",
|
||||
"start": "Start Daemon",
|
||||
"stop": "Stop Daemon"
|
||||
"restart": "Reiniciar Daemon",
|
||||
"start": "Iniciar Daemon",
|
||||
"stop": "Parar Daemon"
|
||||
},
|
||||
"debug": {
|
||||
"debugWithMessage": "Debug - {0}",
|
||||
@@ -153,8 +153,8 @@
|
||||
"decreaseIndent": "Disminuir sangría",
|
||||
"increaseFontSize": "Aumentar tamaño de fuente",
|
||||
"increaseIndent": "Aumentar sangría",
|
||||
"nextError": "Next Error",
|
||||
"previousError": "Previous Error"
|
||||
"nextError": "Siguiente Error",
|
||||
"previousError": "Error Anterior"
|
||||
},
|
||||
"electron": {
|
||||
"couldNotSave": "No se ha podido guardar el sketch. Por favor, copia tu trabajo no guardado en tu editor de texto favorito y reinicia el IDE.",
|
||||
@@ -192,6 +192,7 @@
|
||||
"visit": "Visitar Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Buscar actualizaciones para Arduino IDE",
|
||||
"closeAndInstallButton": "Cerrar e instalar",
|
||||
"closeToInstallNotice": "Cierra el programa e instala la actualización en tu máquina.",
|
||||
"downloadButton": "Descargar",
|
||||
@@ -230,7 +231,7 @@
|
||||
"zipLibrary": "Biblioteca"
|
||||
},
|
||||
"menu": {
|
||||
"advanced": "Advanced",
|
||||
"advanced": "Avanzado",
|
||||
"sketch": "Sketch",
|
||||
"tools": "Herramientas"
|
||||
},
|
||||
@@ -253,10 +254,10 @@
|
||||
"cloud.pull.warn": "Verdadero si se debe advertir a los usuarios antes de sacar un boceto de la nube. El valor predeterminado es verdadero.",
|
||||
"cloud.push.warn": "Verdadero si se debe advertir a los usuarios antes de enviar un boceto a la nube. El valor predeterminado es verdadero.",
|
||||
"cloud.pushpublic.warn": "Verdadero si se debe advertir a los usuarios antes de enviar un boceto público a la nube. El valor predeterminado es verdadero.",
|
||||
"cloud.sketchSyncEnpoint": "El punto final utilizado para empujar y extraer bocetos de un backend. Por defecto, apunta a la API de Arduino Cloud.",
|
||||
"cloud.sketchSyncEndpoint": "El punto final utilizado para empujar y extraer bocetos de un backend. Por defecto, apunta a la API de Arduino Cloud.",
|
||||
"compile": "Compliar",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
"compile.experimental": "True si el IDE debe manejar multiples errores del compilador. False por defecto",
|
||||
"compile.revealRange": "Ajusta cómo se revelan los errores del compilador en el editor después de una verificación/carga fallida. Valores posibles: 'auto': Desplázate verticalmente según sea necesario y revela una línea. 'centrar': Desplázate verticalmente según sea necesario y revela una línea centrada verticalmente. \"superior\": Desplázate verticalmente según sea necesario y revela una línea cerca de la parte superior de la ventana gráfica, optimizada para ver una definición de código. 'centerIfOutsideViewport': Desplázate verticalmente según sea necesario y revela una línea centrada verticalmente sólo si se encuentra fuera de la ventana gráfica. El valor por defecto es '{0}'.",
|
||||
"compile.verbose": "Verdadero para compilación detallada. Falso por defecto",
|
||||
"compile.warnings": "Indica a gcc qué nivel de advertencia usar. Por defecto es \"Ninguno\"",
|
||||
"compilerWarnings": "alertas de compilación",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Ruta del sketchbook no válida: {0}",
|
||||
"invalid.theme": "Tema no válido.",
|
||||
"language.log": "Verdadero si el Servidor de Lenguaje Arduino debe generar archivos de registro en la carpeta del sketch. En caso contrario, falso. Por defecto es falso.",
|
||||
"language.realTimeDiagnostics": "Si está habilitado, el lenguaje proveerá diagnoticos en tiepo real meintras se teclea en el editor. Deshabilitado por defecto.",
|
||||
"manualProxy": "Configuración manual del proxy",
|
||||
"network": "Red",
|
||||
"newSketchbookLocation": "Selecciona la nueva ruta del sketchbook",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Ambos NL & CR",
|
||||
"noLineEndings": "Sin ajuste de línea",
|
||||
"notConnected": "No conectado. Selecciona una placa y un puerto para conectarte automáticamente.",
|
||||
"openSerialPlotter": "Plotter Serie",
|
||||
"timestamp": "Marca de tiempo",
|
||||
"toggleTimestamp": "Alternar la marca de tiempo"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Bisitatu Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Itxi eta instalatu",
|
||||
"closeToInstallNotice": "Itxi softwarea eta instalatu eguneratzea zure makinan.",
|
||||
"downloadButton": "Software eguneratzea",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "Egia bada erabiltzaileek abisua jasoko dute programa bat hodeitik kargatu aurretik. Lehenetsia egia da.",
|
||||
"cloud.push.warn": "Egia bada erabiltzaileek abisua jasoko dute programa bat hodeian gorde aurretik. Lehenetsia egia da.",
|
||||
"cloud.pushpublic.warn": "Egia bada erabiltzaileek abisua jasoko dute programa publiko bat hodeian gorde aurretik. Lehenetsia egia da.",
|
||||
"cloud.sketchSyncEnpoint": "Zerbitzari batean programak gorde eta kargatzeko amaiera-puntua. Lehenetsia Arduino Cloud API da.",
|
||||
"cloud.sketchSyncEndpoint": "Zerbitzari batean programak gorde eta kargatzeko amaiera-puntua. Lehenetsia Arduino Cloud API da.",
|
||||
"compile": "konpilazioa",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Programa bildumaren kokaleku baliogabea: {0}",
|
||||
"invalid.theme": "Itxura baliogabea.",
|
||||
"language.log": "Egia Arduino Language Server-ek egunkari-fitxategiak sortu behar baditu programaren karpetan. Bestela, gezurra. Lehenetsia gezurra da.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Proxyaren eskuzko konfigurazioa",
|
||||
"network": "Sarea",
|
||||
"newSketchbookLocation": "Hautatu programa bilduma berriaren kokalekua",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "NL & CR biak",
|
||||
"noLineEndings": "Lerro amaierarik ez",
|
||||
"notConnected": "Ez dago konektatuta. Hautatu plaka eta ataka automatikoki konektatzeko.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Denbora-zigilua",
|
||||
"toggleTimestamp": "Txandakatu denbora-zigilua"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "بازدید از Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "بستن و نصب",
|
||||
"closeToInstallNotice": "نرم افزار را ببندید و به روز رسانی را روی دستگاه خود نصب کنید.",
|
||||
"downloadButton": "دانلود",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "اگر هشدار دادن به کاربران قبل از کشیدن یک طرح ابری درست می باشد ، پیش فرض ها صحیح است.",
|
||||
"cloud.push.warn": "اگر هشدار دادن به کاربران قبل از ارسال یک طرح ابری درست است پیش فرض ها درست می باشد",
|
||||
"cloud.pushpublic.warn": "اگر هشدار دادن به کاربران قبل از ارسال یک طرح عمومی به فضای درست می باشد پیش فرض ها درست است.",
|
||||
"cloud.sketchSyncEnpoint": "نقطه ای برای ارسال و دریافت طرح ها استفاده می شود . به طور پیش فرض به رابط ابر آردوینو استفاده می کند.",
|
||||
"cloud.sketchSyncEndpoint": "نقطه ای برای ارسال و دریافت طرح ها استفاده می شود . به طور پیش فرض به رابط ابر آردوینو استفاده می کند.",
|
||||
"compile": "کامپایل",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "مکان نامعتبر منبع طرح ها: {0}",
|
||||
"invalid.theme": "طرح زمینه موجود نیست",
|
||||
"language.log": "اگر سرور زبان آردوینو باید فایل های گزارش را در پوشه طرح ایجاد کند درست می باشد. در غیر این صورت، نادرست است. به طور پیش فرض نادرست است.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "پیکربندی دستی پروکسی",
|
||||
"network": "نتورک",
|
||||
"newSketchbookLocation": "مکان جدید منبع طرح ها را مشخص کنید",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "هم NL و هم CR",
|
||||
"noLineEndings": "بدون پایان خط",
|
||||
"notConnected": "متصل نشد. برد و پورت را انتخاب کنید تا بطور خودکار متصل شود.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "برچسب زمانی",
|
||||
"toggleTimestamp": "اتصال برچسب زمان"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Visit Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Close and Install",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.",
|
||||
"cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.",
|
||||
"cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "compile",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
|
||||
"invalid.theme": "Invalid theme.",
|
||||
"language.log": "True, kung dapat na gumawa ng log files ang Arduino Language Server sa mismong sketch folder. False naman kung hindi. Ito ay false, by default. ",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "Network",
|
||||
"newSketchbookLocation": "Select new sketchbook location",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Both NL & CR",
|
||||
"noLineEndings": "No Line Ending",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Timestamp",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Visitez Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Fermer et installer",
|
||||
"closeToInstallNotice": "Fermez le logiciel et installez la mise à jour sur votre machine.",
|
||||
"downloadButton": "Télécharger",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "Vrai si les utilisateurs devrait être averti avant de pull un croquis sur le cloud. Par défaut, la valeur est vrai.",
|
||||
"cloud.push.warn": "Vrai, si les utilisateurs devrait être averti avant de push un croquis sur le cloud. Par défaut, la valeur est vrai.",
|
||||
"cloud.pushpublic.warn": "Vrai si les utilisateurs devrait être avertit avant de publier un croquis public sur le cloud. Vrai par défaut.",
|
||||
"cloud.sketchSyncEnpoint": "L'endpoint est utilisé pour pousser et tirer des croquis à partir du backend. Par défault, il pointe vers l'Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "L'endpoint est utilisé pour pousser et tirer des croquis à partir du backend. Par défault, il pointe vers l'Arduino Cloud API.",
|
||||
"compile": "compiler",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Localisation invalide du croquis : {0}",
|
||||
"invalid.theme": "Thème invalide.",
|
||||
"language.log": "Vrai si le serveur de langage Arduino devrait générer des fichiers logs dans le dossier du croquis. Si non faux. La valeur par défaut est faux.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Configuration manuelle du proxy",
|
||||
"network": "Réseau",
|
||||
"newSketchbookLocation": "Sélectionner la localisation du nouveau croquis.",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Les deux, NL et CR",
|
||||
"noLineEndings": "Pas de fin de ligne",
|
||||
"notConnected": "Déconnecté. Sélectionnez une carte ainsi qu'un port pour vous connecter automatiquement.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "horodatage",
|
||||
"toggleTimestamp": "Activer l'horodatage"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "בקר ב Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "סגור והתקן",
|
||||
"closeToInstallNotice": "סגור את התוכנה והתקן את העדכון על המכונה שלך.",
|
||||
"downloadButton": "הורד",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.",
|
||||
"cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.",
|
||||
"cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "compile",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
|
||||
"invalid.theme": "ערכת נושא לא חוקית.",
|
||||
"language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "רשת",
|
||||
"newSketchbookLocation": "Select new sketchbook location",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Both NL & CR",
|
||||
"noLineEndings": "ללא סיום שורה",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "חותמת זמן",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
@@ -192,6 +192,7 @@
|
||||
"visit": "Visit Arduino.cc"
|
||||
},
|
||||
"ide-updater": {
|
||||
"checkForUpdates": "Check for Arduino IDE updates",
|
||||
"closeAndInstallButton": "Close and Install",
|
||||
"closeToInstallNotice": "Close the software and install the update on your machine.",
|
||||
"downloadButton": "Download",
|
||||
@@ -253,7 +254,7 @@
|
||||
"cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.",
|
||||
"cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.",
|
||||
"cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.",
|
||||
"cloud.sketchSyncEnpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.",
|
||||
"compile": "compile",
|
||||
"compile.experimental": "True if the IDE should handle multiple compiler errors. False by default",
|
||||
"compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.",
|
||||
@@ -271,6 +272,7 @@
|
||||
"invalid.sketchbook.location": "Invalid sketchbook location: {0}",
|
||||
"invalid.theme": "Invalid theme.",
|
||||
"language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.",
|
||||
"language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.",
|
||||
"manualProxy": "Manual proxy configuration",
|
||||
"network": "Network",
|
||||
"newSketchbookLocation": "Select new sketchbook location",
|
||||
@@ -296,6 +298,7 @@
|
||||
"newLineCarriageReturn": "Both NL & CR",
|
||||
"noLineEndings": "No Line Ending",
|
||||
"notConnected": "Not connected. Select a board and a port to connect automatically.",
|
||||
"openSerialPlotter": "Serial Plotter",
|
||||
"timestamp": "Timestamp",
|
||||
"toggleTimestamp": "Toggle Timestamp"
|
||||
},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user