From 028593620b2c730e97384fc8e5526bb7a4f5d13e Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 31 May 2023 13:50:19 +0200 Subject: [PATCH 1/3] chore(cli): Bumped the CLI version `0.33.0-rc1` Signed-off-by: Akos Kitta --- arduino-ide-extension/package.json | 2 +- .../cc/arduino/cli/commands/v1/board_pb.d.ts | 10 +++ .../cc/arduino/cli/commands/v1/board_pb.js | 85 ++++++++++++++++++- .../cc/arduino/cli/commands/v1/common_pb.d.ts | 8 ++ .../cc/arduino/cli/commands/v1/common_pb.js | 62 +++++++++++++- .../arduino/cli/commands/v1/compile_pb.d.ts | 4 + .../cc/arduino/cli/commands/v1/compile_pb.js | 32 ++++++- .../cc/arduino/cli/commands/v1/core_pb.d.ts | 7 ++ .../cc/arduino/cli/commands/v1/core_pb.js | 53 +++++++++++- 9 files changed, 256 insertions(+), 7 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 2d78a1225..ed81b34aa 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -173,7 +173,7 @@ ], "arduino": { "cli": { - "version": "0.32.2" + "version": "0.33.0-rc1" }, "fwuploader": { "version": "2.2.2" diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.d.ts index 8fed14afe..76e70da5f 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.d.ts @@ -18,6 +18,9 @@ export class BoardDetailsRequest extends jspb.Message { getFqbn(): string; setFqbn(value: string): BoardDetailsRequest; + getDoNotExpandBuildProperties(): boolean; + setDoNotExpandBuildProperties(value: boolean): BoardDetailsRequest; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): BoardDetailsRequest.AsObject; @@ -33,6 +36,7 @@ export namespace BoardDetailsRequest { export type AsObject = { instance?: cc_arduino_cli_commands_v1_common_pb.Instance.AsObject, fqbn: string, + doNotExpandBuildProperties: boolean, } } @@ -93,6 +97,11 @@ export class BoardDetailsResponse extends jspb.Message { setIdentificationPropertiesList(value: Array): BoardDetailsResponse; addIdentificationProperties(value?: BoardIdentificationProperties, index?: number): BoardIdentificationProperties; + clearBuildPropertiesList(): void; + getBuildPropertiesList(): Array; + setBuildPropertiesList(value: Array): BoardDetailsResponse; + addBuildProperties(value: string, index?: number): string; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): BoardDetailsResponse.AsObject; @@ -120,6 +129,7 @@ export namespace BoardDetailsResponse { programmersList: Array, debuggingSupported: boolean, identificationPropertiesList: Array, + buildPropertiesList: Array, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.js index 89236154d..da5148eac 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.js @@ -498,7 +498,8 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.prototype.toObject = functi proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.toObject = function(includeInstance, msg) { var f, obj = { instance: (f = msg.getInstance()) && cc_arduino_cli_commands_v1_common_pb.Instance.toObject(includeInstance, f), - fqbn: jspb.Message.getFieldWithDefault(msg, 2, "") + fqbn: jspb.Message.getFieldWithDefault(msg, 2, ""), + doNotExpandBuildProperties: jspb.Message.getBooleanFieldWithDefault(msg, 3, false) }; if (includeInstance) { @@ -544,6 +545,10 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.deserializeBinaryFromReader var value = /** @type {string} */ (reader.readString()); msg.setFqbn(value); break; + case 3: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setDoNotExpandBuildProperties(value); + break; default: reader.skipField(); break; @@ -588,6 +593,13 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.serializeBinaryToWriter = f f ); } + f = message.getDoNotExpandBuildProperties(); + if (f) { + writer.writeBool( + 3, + f + ); + } }; @@ -646,13 +658,31 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.prototype.setFqbn = functio }; +/** + * optional bool do_not_expand_build_properties = 3; + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.prototype.getDoNotExpandBuildProperties = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.cc.arduino.cli.commands.v1.BoardDetailsRequest} returns this + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsRequest.prototype.setDoNotExpandBuildProperties = function(value) { + return jspb.Message.setProto3BooleanField(this, 3, value); +}; + + /** * List of repeated fields within this message type. * @private {!Array} * @const */ -proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.repeatedFields_ = [10,11,13,15]; +proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.repeatedFields_ = [10,11,13,15,16]; @@ -702,7 +732,8 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.toObject = function(includ cc_arduino_cli_commands_v1_common_pb.Programmer.toObject, includeInstance), debuggingSupported: jspb.Message.getBooleanFieldWithDefault(msg, 14, false), identificationPropertiesList: jspb.Message.toObjectList(msg.getIdentificationPropertiesList(), - proto.cc.arduino.cli.commands.v1.BoardIdentificationProperties.toObject, includeInstance) + proto.cc.arduino.cli.commands.v1.BoardIdentificationProperties.toObject, includeInstance), + buildPropertiesList: (f = jspb.Message.getRepeatedField(msg, 16)) == null ? undefined : f }; if (includeInstance) { @@ -801,6 +832,10 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.deserializeBinaryFromReade reader.readMessage(value,proto.cc.arduino.cli.commands.v1.BoardIdentificationProperties.deserializeBinaryFromReader); msg.addIdentificationProperties(value); break; + case 16: + var value = /** @type {string} */ (reader.readString()); + msg.addBuildProperties(value); + break; default: reader.skipField(); break; @@ -934,6 +969,13 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.serializeBinaryToWriter = proto.cc.arduino.cli.commands.v1.BoardIdentificationProperties.serializeBinaryToWriter ); } + f = message.getBuildPropertiesList(); + if (f.length > 0) { + writer.writeRepeatedString( + 16, + f + ); + } }; @@ -1307,6 +1349,43 @@ proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.prototype.clearIdentificat }; +/** + * repeated string build_properties = 16; + * @return {!Array} + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.prototype.getBuildPropertiesList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 16)); +}; + + +/** + * @param {!Array} value + * @return {!proto.cc.arduino.cli.commands.v1.BoardDetailsResponse} returns this + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.prototype.setBuildPropertiesList = function(value) { + return jspb.Message.setField(this, 16, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.cc.arduino.cli.commands.v1.BoardDetailsResponse} returns this + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.prototype.addBuildProperties = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 16, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.cc.arduino.cli.commands.v1.BoardDetailsResponse} returns this + */ +proto.cc.arduino.cli.commands.v1.BoardDetailsResponse.prototype.clearBuildPropertiesList = function() { + return this.setBuildPropertiesList([]); +}; + + diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.d.ts index 7d7926f9e..98d9117fe 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.d.ts @@ -260,6 +260,12 @@ export class Platform extends jspb.Message { getHelp(): HelpResources | undefined; setHelp(value?: HelpResources): Platform; + getIndexed(): boolean; + setIndexed(value: boolean): Platform; + + getMissingMetadata(): boolean; + setMissingMetadata(value: boolean): Platform; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): Platform.AsObject; @@ -285,6 +291,8 @@ export namespace Platform { deprecated: boolean, typeList: Array, help?: HelpResources.AsObject, + indexed: boolean, + missingMetadata: boolean, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.js index dfbc4f507..f0eaaaf44 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.js @@ -1637,7 +1637,9 @@ proto.cc.arduino.cli.commands.v1.Platform.toObject = function(includeInstance, m manuallyInstalled: jspb.Message.getBooleanFieldWithDefault(msg, 9, false), deprecated: jspb.Message.getBooleanFieldWithDefault(msg, 10, false), typeList: (f = jspb.Message.getRepeatedField(msg, 11)) == null ? undefined : f, - help: (f = msg.getHelp()) && proto.cc.arduino.cli.commands.v1.HelpResources.toObject(includeInstance, f) + help: (f = msg.getHelp()) && proto.cc.arduino.cli.commands.v1.HelpResources.toObject(includeInstance, f), + indexed: jspb.Message.getBooleanFieldWithDefault(msg, 13, false), + missingMetadata: jspb.Message.getBooleanFieldWithDefault(msg, 14, false) }; if (includeInstance) { @@ -1724,6 +1726,14 @@ proto.cc.arduino.cli.commands.v1.Platform.deserializeBinaryFromReader = function reader.readMessage(value,proto.cc.arduino.cli.commands.v1.HelpResources.deserializeBinaryFromReader); msg.setHelp(value); break; + case 13: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setIndexed(value); + break; + case 14: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setMissingMetadata(value); + break; default: reader.skipField(); break; @@ -1839,6 +1849,20 @@ proto.cc.arduino.cli.commands.v1.Platform.serializeBinaryToWriter = function(mes proto.cc.arduino.cli.commands.v1.HelpResources.serializeBinaryToWriter ); } + f = message.getIndexed(); + if (f) { + writer.writeBool( + 13, + f + ); + } + f = message.getMissingMetadata(); + if (f) { + writer.writeBool( + 14, + f + ); + } }; @@ -2116,6 +2140,42 @@ proto.cc.arduino.cli.commands.v1.Platform.prototype.hasHelp = function() { }; +/** + * optional bool indexed = 13; + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.Platform.prototype.getIndexed = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 13, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.cc.arduino.cli.commands.v1.Platform} returns this + */ +proto.cc.arduino.cli.commands.v1.Platform.prototype.setIndexed = function(value) { + return jspb.Message.setProto3BooleanField(this, 13, value); +}; + + +/** + * optional bool missing_metadata = 14; + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.Platform.prototype.getMissingMetadata = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 14, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.cc.arduino.cli.commands.v1.Platform} returns this + */ +proto.cc.arduino.cli.commands.v1.Platform.prototype.setMissingMetadata = function(value) { + return jspb.Message.setProto3BooleanField(this, 14, value); +}; + + diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts index 692e2a3d5..a4633d90d 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts @@ -95,6 +95,9 @@ export class CompileRequest extends jspb.Message { getSkipLibrariesDiscovery(): boolean; setSkipLibrariesDiscovery(value: boolean): CompileRequest; + getDoNotExpandBuildProperties(): boolean; + setDoNotExpandBuildProperties(value: boolean): CompileRequest; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): CompileRequest.AsObject; @@ -133,6 +136,7 @@ export namespace CompileRequest { signKey: string, encryptKey: string, skipLibrariesDiscovery: boolean, + doNotExpandBuildProperties: boolean, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js index 64ef4f711..7dcaad1ee 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js @@ -155,7 +155,8 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.toObject = function(includeInsta keysKeychain: jspb.Message.getFieldWithDefault(msg, 25, ""), signKey: jspb.Message.getFieldWithDefault(msg, 26, ""), encryptKey: jspb.Message.getFieldWithDefault(msg, 27, ""), - skipLibrariesDiscovery: jspb.Message.getBooleanFieldWithDefault(msg, 28, false) + skipLibrariesDiscovery: jspb.Message.getBooleanFieldWithDefault(msg, 28, false), + doNotExpandBuildProperties: jspb.Message.getBooleanFieldWithDefault(msg, 29, false) }; if (includeInstance) { @@ -292,6 +293,10 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.deserializeBinaryFromReader = fu var value = /** @type {boolean} */ (reader.readBool()); msg.setSkipLibrariesDiscovery(value); break; + case 29: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setDoNotExpandBuildProperties(value); + break; default: reader.skipField(); break; @@ -488,6 +493,13 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.serializeBinaryToWriter = functi f ); } + f = message.getDoNotExpandBuildProperties(); + if (f) { + writer.writeBool( + 29, + f + ); + } }; @@ -1022,6 +1034,24 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setSkipLibrariesDiscov }; +/** + * optional bool do_not_expand_build_properties = 29; + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.getDoNotExpandBuildProperties = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 29, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.cc.arduino.cli.commands.v1.CompileRequest} returns this + */ +proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setDoNotExpandBuildProperties = function(value) { + return jspb.Message.setProto3BooleanField(this, 29, value); +}; + + /** * List of repeated fields within this message type. diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts index dc8d8b97c..a4d62a8f7 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts @@ -282,6 +282,12 @@ export class PlatformUpgradeResponse extends jspb.Message { setTaskProgress(value?: cc_arduino_cli_commands_v1_common_pb.TaskProgress): PlatformUpgradeResponse; + hasPlatform(): boolean; + clearPlatform(): void; + getPlatform(): cc_arduino_cli_commands_v1_common_pb.Platform | undefined; + setPlatform(value?: cc_arduino_cli_commands_v1_common_pb.Platform): PlatformUpgradeResponse; + + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): PlatformUpgradeResponse.AsObject; static toObject(includeInstance: boolean, msg: PlatformUpgradeResponse): PlatformUpgradeResponse.AsObject; @@ -296,6 +302,7 @@ export namespace PlatformUpgradeResponse { export type AsObject = { progress?: cc_arduino_cli_commands_v1_common_pb.DownloadProgress.AsObject, taskProgress?: cc_arduino_cli_commands_v1_common_pb.TaskProgress.AsObject, + platform?: cc_arduino_cli_commands_v1_common_pb.Platform.AsObject, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js index f9c7e24b6..837c234fe 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js @@ -2064,7 +2064,8 @@ proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.toObject = fu proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.toObject = function(includeInstance, msg) { var f, obj = { progress: (f = msg.getProgress()) && cc_arduino_cli_commands_v1_common_pb.DownloadProgress.toObject(includeInstance, f), - taskProgress: (f = msg.getTaskProgress()) && cc_arduino_cli_commands_v1_common_pb.TaskProgress.toObject(includeInstance, f) + taskProgress: (f = msg.getTaskProgress()) && cc_arduino_cli_commands_v1_common_pb.TaskProgress.toObject(includeInstance, f), + platform: (f = msg.getPlatform()) && cc_arduino_cli_commands_v1_common_pb.Platform.toObject(includeInstance, f) }; if (includeInstance) { @@ -2111,6 +2112,11 @@ proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.deserializeBinaryFromRe reader.readMessage(value,cc_arduino_cli_commands_v1_common_pb.TaskProgress.deserializeBinaryFromReader); msg.setTaskProgress(value); break; + case 3: + var value = new cc_arduino_cli_commands_v1_common_pb.Platform; + reader.readMessage(value,cc_arduino_cli_commands_v1_common_pb.Platform.deserializeBinaryFromReader); + msg.setPlatform(value); + break; default: reader.skipField(); break; @@ -2156,6 +2162,14 @@ proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.serializeBinaryToWriter cc_arduino_cli_commands_v1_common_pb.TaskProgress.serializeBinaryToWriter ); } + f = message.getPlatform(); + if (f != null) { + writer.writeMessage( + 3, + f, + cc_arduino_cli_commands_v1_common_pb.Platform.serializeBinaryToWriter + ); + } }; @@ -2233,6 +2247,43 @@ proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.hasTaskProgre }; +/** + * optional Platform platform = 3; + * @return {?proto.cc.arduino.cli.commands.v1.Platform} + */ +proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.getPlatform = function() { + return /** @type{?proto.cc.arduino.cli.commands.v1.Platform} */ ( + jspb.Message.getWrapperField(this, cc_arduino_cli_commands_v1_common_pb.Platform, 3)); +}; + + +/** + * @param {?proto.cc.arduino.cli.commands.v1.Platform|undefined} value + * @return {!proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse} returns this +*/ +proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.setPlatform = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse} returns this + */ +proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.clearPlatform = function() { + return this.setPlatform(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.PlatformUpgradeResponse.prototype.hasPlatform = function() { + return jspb.Message.getField(this, 3) != null; +}; + + From 58cfdfa515471ba7afca7796dd2bd12af6c1c1e3 Mon Sep 17 00:00:00 2001 From: dankeboy36 Date: Sat, 13 May 2023 13:50:41 +0200 Subject: [PATCH 2/3] feat: set the Arduino context as `workspaceState` Set the VS Code `workspaceState` on fqbn, port, and sketch path changes. VS Code extensions can read this cached state. Signed-off-by: dankeboy36 --- arduino-ide-extension/package.json | 1 + .../browser/arduino-ide-frontend-module.ts | 2 + .../contributions/update-arduino-context.ts | 179 ++++++++++++++++++ .../common/protocol/arduino-context-mapper.ts | 126 ++++++++++++ .../src/common/protocol/boards-service.ts | 1 + .../src/common/protocol/core-service.ts | 57 +++++- .../src/node/boards-service-impl.ts | 2 + .../src/node/core-service-impl.ts | 100 ++++++++-- .../common/arduino-context-mapper.test.ts | 43 +++++ .../test/node/core-service-impl.slow-test.ts | 5 +- package.json | 3 +- yarn.lock | 35 +++- 12 files changed, 523 insertions(+), 31 deletions(-) create mode 100644 arduino-ide-extension/src/browser/contributions/update-arduino-context.ts create mode 100644 arduino-ide-extension/src/common/protocol/arduino-context-mapper.ts create mode 100644 arduino-ide-extension/src/test/common/arduino-context-mapper.test.ts diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index ed81b34aa..8f7e2ead7 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -105,6 +105,7 @@ "temp-dir": "^2.0.0", "tree-kill": "^1.2.1", "util": "^0.12.5", + "vscode-arduino-api": "^0.1.1-alpha.4", "which": "^1.3.1" }, "devDependencies": { diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 89d13fd93..8c9bcd20a 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -354,6 +354,7 @@ import { FileResourceResolver as TheiaFileResourceResolver } from '@theia/filesy import { StylingParticipant } from '@theia/core/lib/browser/styling-service'; import { MonacoEditorMenuContribution } from './theia/monaco/monaco-menu'; import { MonacoEditorMenuContribution as TheiaMonacoEditorMenuContribution } from '@theia/monaco/lib/browser/monaco-menu'; +import { UpdateArduinoContext } from './contributions/update-arduino-context'; // Hack to fix copy/cut/paste issue after electron version update in Theia. // https://github.com/eclipse-theia/theia/issues/12487 @@ -747,6 +748,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { Contribution.configure(bind, Account); Contribution.configure(bind, CloudSketchbookContribution); Contribution.configure(bind, CreateCloudCopy); + Contribution.configure(bind, UpdateArduinoContext); bindContributionProvider(bind, StartupTaskProvider); bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window diff --git a/arduino-ide-extension/src/browser/contributions/update-arduino-context.ts b/arduino-ide-extension/src/browser/contributions/update-arduino-context.ts new file mode 100644 index 000000000..e826d38a9 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/update-arduino-context.ts @@ -0,0 +1,179 @@ +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import URI from '@theia/core/lib/common/uri'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin'; +import type { ArduinoState } from 'vscode-arduino-api'; +import { + BoardsService, + CompileSummary, + Port, + isCompileSummary, +} from '../../common/protocol'; +import { + toApiBoardDetails, + toApiCompileSummary, + toApiPort, +} from '../../common/protocol/arduino-context-mapper'; +import type { BoardsConfig } from '../boards/boards-config'; +import { BoardsDataStore } from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { SketchContribution } from './contribution'; + +interface UpdateWorkspaceStateParams { + readonly key: keyof T; + readonly value: T[keyof T]; +} + +/** + * Contribution for setting the VS Code [`workspaceState`](https://code.visualstudio.com/api/references/vscode-api#workspace) on Arduino IDE context changes, such as FQBN, selected port, and sketch path changes via commands. + * See [`vscode-arduino-api`](https://www.npmjs.com/package/vscode-arduino-api) for more details. + */ +@injectable() +export class UpdateArduinoContext extends SketchContribution { + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(BoardsDataStore) + private readonly boardsDataStore: BoardsDataStore; + @inject(HostedPluginSupport) + private readonly hostedPluginSupport: HostedPluginSupport; + + private readonly toDispose = new DisposableCollection(); + + override onStart(): void { + this.toDispose.pushAll([ + this.boardsServiceProvider.onBoardsConfigChanged((config) => + this.updateBoardsConfig(config) + ), + this.sketchServiceClient.onCurrentSketchDidChange((sketch) => + this.updateSketchPath(sketch) + ), + this.configService.onDidChangeDataDirUri((dataDirUri) => + this.updateDataDirPath(dataDirUri) + ), + this.configService.onDidChangeSketchDirUri((userDirUri) => + this.updateUserDirPath(userDirUri) + ), + this.commandService.onDidExecuteCommand(({ commandId, args }) => { + if ( + commandId === 'arduino.languageserver.notifyBuildDidComplete' && + isCompileSummary(args[0]) + ) { + this.updateCompileSummary(args[0]); + } + }), + this.boardsDataStore.onChanged((fqbn) => { + const selectedFqbn = + this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn; + if (selectedFqbn && fqbn.includes(selectedFqbn)) { + this.updateBoardDetails(selectedFqbn); + } + }), + ]); + } + + override onReady(): void { + this.boardsServiceProvider.reconciled.then(() => { + this.updateBoardsConfig(this.boardsServiceProvider.boardsConfig); + }); + this.updateSketchPath(this.sketchServiceClient.tryGetCurrentSketch()); + this.updateUserDirPath(this.configService.tryGetSketchDirUri()); + this.updateDataDirPath(this.configService.tryGetDataDirUri()); + } + + onStop(): void { + this.toDispose.dispose(); + } + + private async updateSketchPath( + sketch: CurrentSketch | undefined + ): Promise { + const sketchPath = CurrentSketch.isValid(sketch) + ? new URI(sketch.uri).path.fsPath() + : undefined; + return this.updateWorkspaceState({ key: 'sketchPath', value: sketchPath }); + } + + private async updateCompileSummary( + compileSummary: CompileSummary + ): Promise { + const apiCompileSummary = toApiCompileSummary(compileSummary); + return this.updateWorkspaceState({ + key: 'compileSummary', + value: apiCompileSummary, + }); + } + + private async updateBoardsConfig( + boardsConfig: BoardsConfig.Config + ): Promise { + const fqbn = boardsConfig.selectedBoard?.fqbn; + const port = boardsConfig.selectedPort; + await this.updateFqbn(fqbn); + await this.updateBoardDetails(fqbn); + await this.updatePort(port); + } + + private async updateFqbn(fqbn: string | undefined): Promise { + await this.updateWorkspaceState({ key: 'fqbn', value: fqbn }); + } + + private async updateBoardDetails(fqbn: string | undefined): Promise { + const unset = () => + this.updateWorkspaceState({ key: 'boardDetails', value: undefined }); + if (!fqbn) { + return unset(); + } + const [details, persistedData] = await Promise.all([ + this.boardsService.getBoardDetails({ fqbn }), + this.boardsDataStore.getData(fqbn), + ]); + if (!details) { + return unset(); + } + const apiBoardDetails = toApiBoardDetails({ + ...details, + configOptions: + BoardsDataStore.Data.EMPTY === persistedData + ? details.configOptions + : persistedData.configOptions.slice(), + }); + return this.updateWorkspaceState({ + key: 'boardDetails', + value: apiBoardDetails, + }); + } + + private async updatePort(port: Port | undefined): Promise { + const apiPort = port && toApiPort(port); + return this.updateWorkspaceState({ key: 'port', value: apiPort }); + } + + private async updateUserDirPath(userDirUri: URI | undefined): Promise { + const userDirPath = userDirUri?.path.fsPath(); + return this.updateWorkspaceState({ + key: 'userDirPath', + value: userDirPath, + }); + } + + private async updateDataDirPath(dataDirUri: URI | undefined): Promise { + const dataDirPath = dataDirUri?.path.fsPath(); + return this.updateWorkspaceState({ + key: 'dataDirPath', + value: dataDirPath, + }); + } + + private async updateWorkspaceState( + params: UpdateWorkspaceStateParams + ): Promise { + await this.hostedPluginSupport.didStart; + return this.commandService.executeCommand( + 'vscodeArduinoAPI.updateState', + params + ); + } +} diff --git a/arduino-ide-extension/src/common/protocol/arduino-context-mapper.ts b/arduino-ide-extension/src/common/protocol/arduino-context-mapper.ts new file mode 100644 index 000000000..ede24fe1c --- /dev/null +++ b/arduino-ide-extension/src/common/protocol/arduino-context-mapper.ts @@ -0,0 +1,126 @@ +import type { + Port as APIPort, + BoardDetails as ApiBoardDetails, + BuildProperties as ApiBuildProperties, + CompileSummary as ApiCompileSummary, + ConfigOption as ApiConfigOption, + ConfigValue as ApiConfigValue, + Tool as ApiTool, +} from 'vscode-arduino-api'; +import type { + BoardDetails, + CompileSummary, + ConfigOption, + ConfigValue, + Port, + Tool, +} from '../protocol'; + +export function toApiCompileSummary( + compileSummary: CompileSummary +): ApiCompileSummary { + const { + buildPath, + buildProperties, + boardPlatform, + buildPlatform, + executableSectionsSize, + usedLibraries, + } = compileSummary; + return { + buildPath, + buildProperties: toApiBuildProperties(buildProperties), + executableSectionsSize: executableSectionsSize, + boardPlatform, + buildPlatform, + usedLibraries, + }; +} + +export function toApiPort(port: Port): APIPort | undefined { + const { + hardwareId = '', + properties = {}, + address, + protocol, + protocolLabel, + addressLabel: label, + } = port; + return { + label, + address, + hardwareId, + properties, + protocol, + protocolLabel, + }; +} + +export function toApiBoardDetails(boardDetails: BoardDetails): ApiBoardDetails { + const { fqbn, programmers, configOptions, requiredTools } = boardDetails; + return { + buildProperties: toApiBuildProperties(boardDetails.buildProperties), + configOptions: configOptions.map(toApiConfigOption), + fqbn, + programmers, + toolsDependencies: requiredTools.map(toApiTool), + }; +} + +function toApiConfigOption(configOption: ConfigOption): ApiConfigOption { + const { label, values, option } = configOption; + return { + optionLabel: label, + option, + values: values.map(toApiConfigValue), + }; +} + +function toApiConfigValue(configValue: ConfigValue): ApiConfigValue { + const { label, selected, value } = configValue; + return { + selected, + value, + valueLabel: label, + }; +} + +function toApiTool(toolDependency: Tool): ApiTool { + const { name, packager, version } = toolDependency; + return { + name, + packager, + version, + }; +} + +const propertySep = '='; + +function parseProperty( + property: string +): [key: string, value: string] | undefined { + const segments = property.split(propertySep); + if (segments.length < 2) { + console.warn(`Could not parse build property: ${property}.`); + return undefined; + } + + const [key, ...rest] = segments; + if (!key) { + console.warn(`Could not determine property key from raw: ${property}.`); + return undefined; + } + const value = rest.join(propertySep); + return [key, value]; +} + +export function toApiBuildProperties(properties: string[]): ApiBuildProperties { + return properties.reduce((acc, curr) => { + const entry = parseProperty(curr); + if (entry) { + const [key, value] = entry; + acc[key] = value; + } + return acc; + }, >{}); +} diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index c955b9462..7e2f77555 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -441,6 +441,7 @@ export interface BoardDetails { readonly debuggingSupported: boolean; readonly VID: string; readonly PID: string; + readonly buildProperties: string[]; } export interface Tool { diff --git a/arduino-ide-extension/src/common/protocol/core-service.ts b/arduino-ide-extension/src/common/protocol/core-service.ts index 7dfcfb896..2a683370d 100644 --- a/arduino-ide-extension/src/common/protocol/core-service.ts +++ b/arduino-ide-extension/src/common/protocol/core-service.ts @@ -5,13 +5,11 @@ import type { Range, Position, } from '@theia/core/shared/vscode-languageserver-protocol'; -import type { - BoardUserField, - Port, -} from '../../common/protocol/boards-service'; +import type { BoardUserField, Port, Installable } from '../../common/protocol/'; import type { Programmer } from './boards-service'; import type { Sketch } from './sketches-service'; import { IndexUpdateSummary } from './notification-service'; +import type { CompileSummary as ApiCompileSummary } from 'vscode-arduino-api'; export const CompilerWarningLiterals = [ 'None', @@ -19,7 +17,7 @@ export const CompilerWarningLiterals = [ 'More', 'All', ] as const; -export type CompilerWarnings = typeof CompilerWarningLiterals[number]; +export type CompilerWarnings = (typeof CompilerWarningLiterals)[number]; export namespace CompilerWarnings { export function labelOf(warning: CompilerWarnings): string { return CompilerWarningLabels[warning]; @@ -103,6 +101,53 @@ export namespace CoreError { } } +export interface InstalledPlatformReference { + readonly id: string; + readonly version: Installable.Version; + /** + * Absolute filesystem path. + */ + readonly installDir: string; + readonly packageUrl: string; +} + +export interface ExecutableSectionSize { + readonly name: string; + readonly size: number; + readonly maxSize: number; +} + +export interface CompileSummary { + readonly buildPath: string; + /** + * To be compatible with the `vscode-arduino-tools` API. + * @deprecated Use `buildPath` instead. Use Theia or VS Code URI to convert to an URI string on the client side. + */ + readonly buildOutputUri: string; + readonly usedLibraries: ApiCompileSummary['usedLibraries']; + readonly executableSectionsSize: ExecutableSectionSize[]; + readonly boardPlatform?: InstalledPlatformReference | undefined; + readonly buildPlatform?: InstalledPlatformReference | undefined; + readonly buildProperties: string[]; +} + +export function isCompileSummary(arg: unknown): arg is CompileSummary { + return ( + Boolean(arg) && + typeof arg === 'object' && + (arg).buildPath !== undefined && + typeof (arg).buildPath === 'string' && + (arg).buildOutputUri !== undefined && + typeof (arg).buildOutputUri === 'string' && + (arg).executableSectionsSize !== undefined && + Array.isArray((arg).executableSectionsSize) && + (arg).usedLibraries !== undefined && + Array.isArray((arg).usedLibraries) && + (arg).buildProperties !== undefined && + Array.isArray((arg).buildProperties) + ); +} + export const CoreServicePath = '/services/core-service'; export const CoreService = Symbol('CoreService'); export interface CoreService { @@ -132,7 +177,7 @@ export interface CoreService { } export const IndexTypeLiterals = ['platform', 'library'] as const; -export type IndexType = typeof IndexTypeLiterals[number]; +export type IndexType = (typeof IndexTypeLiterals)[number]; export namespace IndexType { export function is(arg: unknown): arg is IndexType { return ( diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index e04aa909f..a2db13193 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -155,6 +155,7 @@ export class BoardsServiceImpl VID = prop.get('vid') || ''; PID = prop.get('pid') || ''; } + const buildProperties = detailsResp.getBuildPropertiesList(); return { fqbn, @@ -164,6 +165,7 @@ export class BoardsServiceImpl debuggingSupported, VID, PID, + buildProperties }; } diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index 5ab4506fa..cf9bfd6a8 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -8,6 +8,8 @@ import { CompilerWarnings, CoreService, CoreError, + CompileSummary, + isCompileSummary, } from '../common/protocol/core-service'; import { CompileRequest, @@ -35,12 +37,15 @@ import { firstToUpperCase, notEmpty } from '../common/utils'; import { ServiceError } from './service-error'; import { ExecuteWithProgress, ProgressResponse } from './grpc-progressible'; import { BoardDiscovery } from './board-discovery'; +import { Mutable } from '@theia/core/lib/common/types'; namespace Uploadable { export type Request = UploadRequest | UploadUsingProgrammerRequest; export type Response = UploadResponse | UploadUsingProgrammerResponse; } +type CompileSummaryFragment = Partial>; + @injectable() export class CoreServiceImpl extends CoreClientAware implements CoreService { @inject(ResponseService) @@ -58,23 +63,13 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { async compile(options: CoreService.Options.Compile): Promise { const coreClient = await this.coreClient; const { client, instance } = coreClient; - let buildPath: string | undefined = undefined; + const compileSummary = {}; const progressHandler = this.createProgressHandler(options); - const buildPathHandler = (response: CompileResponse) => { - const currentBuildPath = response.getBuildPath(); - if (currentBuildPath) { - buildPath = currentBuildPath; - } else { - if (!!buildPath && currentBuildPath !== buildPath) { - throw new Error( - `The CLI has already provided a build path: <${buildPath}>, and IDE received a new build path value: <${currentBuildPath}>.` - ); - } - } - }; + const compileSummaryHandler = (response: CompileResponse) => + updateCompileSummary(compileSummary, response); const handler = this.createOnDataHandler( progressHandler, - buildPathHandler + compileSummaryHandler ); const request = this.compileRequest(options, instance); return new Promise((resolve, reject) => { @@ -111,31 +106,35 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { .on('end', resolve); }).finally(() => { handler.dispose(); - if (!buildPath) { + if (!isCompileSummary(compileSummary)) { console.error( - `Have not received the build path from the CLI while running the compilation.` + `Have not received the full compile summary from the CLI while running the compilation. ${JSON.stringify( + compileSummary + )}` ); } else { - this.fireBuildDidComplete(FileUri.create(buildPath).toString()); + this.fireBuildDidComplete(compileSummary); } }); } // This executes on the frontend, the VS Code extension receives it, and sends an `ino/buildDidComplete` notification to the language server. - private fireBuildDidComplete(buildOutputUri: string): void { + private fireBuildDidComplete(compileSummary: CompileSummary): void { const params = { - buildOutputUri, + ...compileSummary, }; console.info( `Executing 'arduino.languageserver.notifyBuildDidComplete' with ${JSON.stringify( - params + params.buildOutputUri )}` ); this.commandService .executeCommand('arduino.languageserver.notifyBuildDidComplete', params) .catch((err) => console.error( - `Unexpected error when firing event on build did complete. ${buildOutputUri}`, + `Unexpected error when firing event on build did complete. ${JSON.stringify( + params.buildOutputUri + )}`, err ) ); @@ -461,3 +460,62 @@ namespace StreamingResponse { readonly handlers?: ((response: R) => void)[]; } } + +function updateCompileSummary( + compileSummary: CompileSummaryFragment, + response: CompileResponse +): CompileSummaryFragment { + const buildPath = response.getBuildPath(); + if (buildPath) { + compileSummary.buildPath = buildPath; + compileSummary.buildOutputUri = FileUri.create(buildPath).toString(); + } + const executableSectionsSize = response.getExecutableSectionsSizeList(); + if (executableSectionsSize) { + compileSummary.executableSectionsSize = executableSectionsSize.map((item) => + item.toObject(false) + ); + } + const usedLibraries = response.getUsedLibrariesList(); + if (usedLibraries) { + compileSummary.usedLibraries = usedLibraries.map((item) => { + const object = item.toObject(false); + const library = { + ...object, + architectures: object.architecturesList, + types: object.typesList, + examples: object.examplesList, + providesIncludes: object.providesIncludesList, + properties: object.propertiesMap.reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {} as Record), + compatibleWith: object.compatibleWithMap.reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {} as Record), + } as const; + const mutable = >>library; + delete mutable.architecturesList; + delete mutable.typesList; + delete mutable.examplesList; + delete mutable.providesIncludesList; + delete mutable.propertiesMap; + delete mutable.compatibleWithMap; + return library; + }); + } + const boardPlatform = response.getBoardPlatform(); + if (boardPlatform) { + compileSummary.buildPlatform = boardPlatform.toObject(false); + } + const buildPlatform = response.getBuildPlatform(); + if (buildPlatform) { + compileSummary.buildPlatform = buildPlatform.toObject(false); + } + const buildProperties = response.getBuildPropertiesList(); + if (buildProperties) { + compileSummary.buildProperties = buildProperties.slice(); + } + return compileSummary; +} diff --git a/arduino-ide-extension/src/test/common/arduino-context-mapper.test.ts b/arduino-ide-extension/src/test/common/arduino-context-mapper.test.ts new file mode 100644 index 000000000..23727bffc --- /dev/null +++ b/arduino-ide-extension/src/test/common/arduino-context-mapper.test.ts @@ -0,0 +1,43 @@ +import { expect } from 'chai'; +import { toApiBuildProperties } from '../../common/protocol/arduino-context-mapper'; + +describe('arduino-context-mapper', () => { + describe('toApiBuildProperties', () => { + it('should parse an array of build properties string into a record', () => { + const expected = { + foo: 'alma', + bar: '36', + baz: 'false', + }; + const actual = toApiBuildProperties(['foo=alma', 'bar=36', 'baz=false']); + expect(actual).to.be.deep.equal(expected); + }); + + it('should not skip build property key with empty value', () => { + const expected = { + foo: '', + }; + const actual = toApiBuildProperties(['foo=']); + expect(actual).to.be.deep.equal(expected); + }); + + it('should skip invalid entries', () => { + const expected = { + foo: 'alma', + bar: '36', + baz: '-DARDUINO_USB_CDC_ON_BOOT=0', + }; + const actual = toApiBuildProperties([ + 'foo=alma', + 'invalid', + '=invalid2', + '=invalid3=', + '=', + '==', + 'bar=36', + 'baz=-DARDUINO_USB_CDC_ON_BOOT=0', + ]); + expect(actual).to.be.deep.equal(expected); + }); + }); +}); diff --git a/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts b/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts index faac7b6c7..0a0fd253c 100644 --- a/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts +++ b/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts @@ -9,6 +9,7 @@ import { BoardsService, CoreService, SketchesService, + isCompileSummary, } from '../../common/protocol'; import { createBaseContainer, startDaemon } from './test-bindings'; @@ -31,7 +32,7 @@ describe('core-service-impl', () => { afterEach(() => toDispose.dispose()); describe('compile', () => { - it('should execute a command with the build path', async function () { + it('should execute a command with the compile summary, including the build path', async function () { this.timeout(testTimeout); const coreService = container.get(CoreService); const sketchesService = container.get(SketchesService); @@ -56,7 +57,7 @@ describe('core-service-impl', () => { const [, args] = executedBuildDidCompleteCommands[0]; expect(args.length).to.be.equal(1); const arg = args[0]; - expect(typeof arg).to.be.equal('object'); + expect(isCompileSummary(arg)).to.be.true; expect('buildOutputUri' in arg).to.be.true; expect(arg.buildOutputUri).to.be.not.undefined; diff --git a/package.json b/package.json index 9c9c00f56..f5c4cc9a0 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "watch": "lerna run watch --parallel", "test": "lerna run test", "test:slow": "lerna run test:slow", - "download:plugins": "theia download:plugins", + "download:plugins": "theia download:plugins --ignore-errors", "update:version": "node ./scripts/update-version.js", "i18n:generate": "theia nls-extract -e vscode -f \"+(arduino-ide-extension|electron-app|plugins)/**/*.ts?(x)\" -o ./i18n/en.json", "i18n:check": "yarn i18n:generate && git add -N ./i18n && git diff --exit-code ./i18n", @@ -70,6 +70,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-api": "https://github.com/dankeboy36/vscode-arduino-api/releases/download/0.1.0/vscode-arduino-api-0.1.0.vsix", "vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.8.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", diff --git a/yarn.lock b/yarn.lock index 58a12fc91..b5b44ab09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3216,6 +3216,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.5.tgz#b1d2f772142a301538fae9bdf9cf15b9f2573a29" integrity sha512-hKB88y3YHL8oPOs/CNlaXtjWn93+Bs48sDQR37ZUqG2tLeCS7EA1cmnkKsuQsub9OKEB/y/Rw9zqJqqNSbqVlQ== +"@types/vscode@^1.78.0": + version "1.78.0" + resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.78.0.tgz#b5600abce8855cf21fb32d0857bcd084b1f83069" + integrity sha512-LJZIJpPvKJ0HVQDqfOy6W4sNKUBBwyDu1Bs8chHBZOe9MNuKTJtidgZ2bqjhmmWpUb0TIIqv47BFUcVmAsgaVA== + "@types/which@^1.3.1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf" @@ -3998,6 +4003,14 @@ arduino-serial-plotter-webapp@0.2.0: resolved "https://registry.yarnpkg.com/arduino-serial-plotter-webapp/-/arduino-serial-plotter-webapp-0.2.0.tgz#90d61ad7ed1452f70fd226ff25eccb36c1ab1a4f" integrity sha512-AxQIsKr6Mf8K1c3kj+ojjFvE9Vz8cUqJqRink6/myp/ranEGwsQQ83hziktkPKZvBQshqrMH8nzoGIY2Z3A2OA== +ardunno-cli@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ardunno-cli/-/ardunno-cli-0.1.2.tgz#145d998231b34b33bf70f7fc6e5be6497191f708" + integrity sha512-8PTBMDS2ofe2LJZZKHw/MgfXgDwpiImXJcBeqeZ6lcTSDqQNMJpEIjcCdPcxbsQbJXRRfZZ4nn6G/gXwEuJPpw== + dependencies: + nice-grpc-common "^2.0.2" + protobufjs "^7.2.3" + are-we-there-yet@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" @@ -10750,6 +10763,13 @@ nested-error-stacks@^2.1.1: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== +nice-grpc-common@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz#e6aeebb2bd19d87114b351e291e30d79dd38acf7" + integrity sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ== + dependencies: + ts-error "^1.0.6" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -12196,7 +12216,7 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== -protobufjs@^7.0.0: +protobufjs@^7.0.0, protobufjs@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2" integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg== @@ -14362,6 +14382,11 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== +ts-error@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/ts-error/-/ts-error-1.0.6.tgz#277496f2a28de6c184cfce8dfd5cdd03a4e6b0fc" + integrity sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA== + ts-md5@^1.2.2: version "1.3.1" resolved "https://registry.yarnpkg.com/ts-md5/-/ts-md5-1.3.1.tgz#f5b860c0d5241dd9bb4e909dd73991166403f511" @@ -14959,6 +14984,14 @@ vinyl@^2.2.1: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" +vscode-arduino-api@^0.1.1-alpha.4: + version "0.1.1-alpha.4" + resolved "https://registry.yarnpkg.com/vscode-arduino-api/-/vscode-arduino-api-0.1.1-alpha.4.tgz#37b95f47f74cb491b2a8826849a4ccbd406fd526" + integrity sha512-1W+UK1ckbaYrqQYMLT+oziMzzhvQ5MgUTD8lP/6U6TmH6T0SOlhX/FXZAkfDeyyylcgmA6ItNfkNUskzLy0MEQ== + dependencies: + "@types/vscode" "^1.78.0" + ardunno-cli "^0.1.2" + vscode-jsonrpc@8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz#cb9989c65e219e18533cc38e767611272d274c94" From 9518fdf4c4a878ad1c554371f72cd9169304579e Mon Sep 17 00:00:00 2001 From: dankeboy36 Date: Tue, 30 May 2023 21:55:24 +0200 Subject: [PATCH 3/3] fix: force plugin activation order api plugin must start before any tool VSIX without explicitly updating the `extensionDependencies` with the API. Signed-off-by: dankeboy36 --- .../browser/theia/plugin-ext/hosted-plugin.ts | 47 ++++++++++++++++--- package.json | 2 +- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/arduino-ide-extension/src/browser/theia/plugin-ext/hosted-plugin.ts b/arduino-ide-extension/src/browser/theia/plugin-ext/hosted-plugin.ts index 326e02ee4..8491357a4 100644 --- a/arduino-ide-extension/src/browser/theia/plugin-ext/hosted-plugin.ts +++ b/arduino-ide-extension/src/browser/theia/plugin-ext/hosted-plugin.ts @@ -1,7 +1,10 @@ -import { Emitter, Event, JsonRpcProxy } from '@theia/core'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Emitter, Event } from '@theia/core/lib/common/event'; import { injectable, interfaces } from '@theia/core/shared/inversify'; -import { HostedPluginServer } from '@theia/plugin-ext/lib/common/plugin-protocol'; -import { HostedPluginSupport as TheiaHostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin'; +import { + PluginContributions, + HostedPluginSupport as TheiaHostedPluginSupport, +} from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin'; @injectable() export class HostedPluginSupport extends TheiaHostedPluginSupport { @@ -10,7 +13,7 @@ export class HostedPluginSupport extends TheiaHostedPluginSupport { override onStart(container: interfaces.Container): void { super.onStart(container); - this.hostedPluginServer.onDidCloseConnection(() => + this['server'].onDidCloseConnection(() => this.onDidCloseConnectionEmitter.fire() ); } @@ -28,8 +31,38 @@ export class HostedPluginSupport extends TheiaHostedPluginSupport { return this.onDidCloseConnectionEmitter.event; } - private get hostedPluginServer(): JsonRpcProxy { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return (this as any).server; + protected override startPlugins( + contributionsByHost: Map, + toDisconnect: DisposableCollection + ): Promise { + reorderPlugins(contributionsByHost); + return super.startPlugins(contributionsByHost, toDisconnect); } } + +/** + * Force the `vscode-arduino-ide` API to activate before any Arduino IDE tool VSIX. + * + * Arduino IDE tool VISXs are not forced to declare the `vscode-arduino-api` as a `extensionDependencies`, + * but the API must activate before any tools. This in place sorting helps to bypass Theia's plugin resolution + * without forcing tools developers to add `vscode-arduino-api` to the `extensionDependencies`. + */ +function reorderPlugins( + contributionsByHost: Map +): void { + for (const [, contributions] of contributionsByHost) { + const apiPluginIndex = contributions.findIndex(isArduinoAPI); + if (apiPluginIndex >= 0) { + const apiPlugin = contributions[apiPluginIndex]; + contributions.splice(apiPluginIndex, 1); + contributions.unshift(apiPlugin); + } + } +} + +function isArduinoAPI(pluginContribution: PluginContributions): boolean { + return ( + pluginContribution.plugin.metadata.model.id === + 'dankeboy36.vscode-arduino-api' + ); +} diff --git a/package.json b/package.json index f5c4cc9a0..11cdbec37 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "watch": "lerna run watch --parallel", "test": "lerna run test", "test:slow": "lerna run test:slow", - "download:plugins": "theia download:plugins --ignore-errors", + "download:plugins": "theia download:plugins", "update:version": "node ./scripts/update-version.js", "i18n:generate": "theia nls-extract -e vscode -f \"+(arduino-ide-extension|electron-app|plugins)/**/*.ts?(x)\" -o ./i18n/en.json", "i18n:check": "yarn i18n:generate && git add -N ./i18n && git diff --exit-code ./i18n",