diff --git a/arduino-ide-extension/build/arduino-cli.darwin b/arduino-ide-extension/build/arduino-cli.darwin index 8e1e3574..ac7cb2d5 100755 Binary files a/arduino-ide-extension/build/arduino-cli.darwin and b/arduino-ide-extension/build/arduino-cli.darwin differ diff --git a/arduino-ide-extension/build/arduino-cli.linux b/arduino-ide-extension/build/arduino-cli.linux index 2d2beeb7..7a5c9cc4 100755 Binary files a/arduino-ide-extension/build/arduino-cli.linux and b/arduino-ide-extension/build/arduino-cli.linux differ diff --git a/arduino-ide-extension/build/arduino-cli.win32 b/arduino-ide-extension/build/arduino-cli.win32 index bf0a048e..407e4e0d 100755 Binary files a/arduino-ide-extension/build/arduino-cli.win32 and b/arduino-ide-extension/build/arduino-cli.win32 differ diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx index ea346a1d..415aeb61 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -12,6 +12,7 @@ import { ConnectedBoards } from './components/connected-boards'; import { CoreService } from '../common/protocol/core-service'; import { WorkspaceServiceExt } from './workspace-service-ext'; import { ToolOutputServiceClient } from '../common/protocol/tool-output-service'; +import { ConfirmDialog } from '@theia/core/lib/browser'; @injectable() @@ -65,6 +66,10 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr isVisible: widget => this.isArduinoEditor(widget), isEnabled: widget => this.isArduinoEditor(widget), execute: async widget => { + if (widget instanceof EditorWidget) { + await widget.saveable.save(); + } + const uri = this.toUri(widget); if (uri) { const result = await this.coreService.compile({ uri: uri.toString() }); @@ -76,10 +81,19 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr isVisible: widget => this.isArduinoEditor(widget), isEnabled: widget => this.isArduinoEditor(widget), execute: async widget => { + if (widget instanceof EditorWidget) { + await widget.saveable.save(); + } + const uri = this.toUri(widget); - if (uri) { - const result = await this.coreService.upload({ uri: uri.toString() }); - console.log('upload result', result); + if (!uri) { + return; + } + + try { + await this.coreService.upload({ uri: uri.toString() }); + } catch (e) { + new ConfirmDialog({ title: "Error during upload", msg: e.toString(), ok: "Ok" }).open(); } } }); diff --git a/arduino-ide-extension/src/browser/components/connected-boards.tsx b/arduino-ide-extension/src/browser/components/connected-boards.tsx index 8704862c..51137995 100644 --- a/arduino-ide-extension/src/browser/components/connected-boards.tsx +++ b/arduino-ide-extension/src/browser/components/connected-boards.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; -// TODO: make this `async`. -// import { Async } from 'react-select/lib/Async'; -import { BoardsService, AttachedBoard } from '../../common/protocol/boards-service'; +import { BoardsService, Board } from '../../common/protocol/boards-service'; +import { SelectBoardDialog } from './select-board-dialog'; export class ConnectedBoards extends React.Component { static TOOLBAR_ID: 'connected-boards-toolbar'; @@ -12,23 +11,28 @@ export class ConnectedBoards extends React.Component 0) { content = this.state.boards.map((b, i) => ); } else { + let label; + if (this.state.boardsLoading) { + label = "Loading ..."; + } else { + label = "No board attached"; + } content = [ ]; } return
- + + { content } + + + { !!this.state.otherBoard && } + +
; } @@ -38,26 +42,38 @@ export class ConnectedBoards extends React.Component) { - const selectedBoard = (this.state.boards || [])[parseInt(evt.target.value, 10)]; + const selection = evt.target.value; + if (selection === "select-other" || selection === "selected-other") { + let selectedBoard = this.state.otherBoard; + if (selection === "select-other" || !selectedBoard) { + selectedBoard = await new SelectBoardDialog(this.props.boardsService).open(); + } + if (!selectedBoard) { + return; + } + + await this.props.boardsService.selectBoard(selectedBoard); + this.setState({otherBoard: selectedBoard, selection: "selected-other"}); + return; + } + + const selectedBoard = (this.state.boards || [])[parseInt(selection, 10)]; if (!selectedBoard) { return; } - this.selectBoard(selectedBoard); - } - - protected async selectBoard(board: AttachedBoard) { - await this.props.boardsService.selectBoard(board); - this.setState({ current: board }); + await this.props.boardsService.selectBoard(selectedBoard); + this.setState({selection}); } } @@ -70,8 +86,9 @@ export namespace ConnectedBoards { export interface State { boardsLoading: boolean; - boards?: AttachedBoard[]; - current?: AttachedBoard; + boards?: Board[]; + otherBoard?: Board; + selection?: string; } export namespace Styles { diff --git a/arduino-ide-extension/src/browser/components/select-board-dialog.tsx b/arduino-ide-extension/src/browser/components/select-board-dialog.tsx new file mode 100644 index 00000000..13de977a --- /dev/null +++ b/arduino-ide-extension/src/browser/components/select-board-dialog.tsx @@ -0,0 +1,103 @@ +import { AbstractDialog, ReactRenderer, Message } from "@theia/core/lib/browser"; +import { Board, BoardsService } from "../../common/protocol/boards-service"; +import * as React from 'react'; + +interface BoardGroup { + name: string + boards: Board[] +} + +class DialogContentRenderer extends ReactRenderer { + protected availableBoards: BoardGroup[] = [ ]; + protected searchTerm = ""; + + constructor(protected readonly boardsService: BoardsService, protected readonly onSelect: (b: Board) => void) { + super(); + this.search(); + } + + doRender(): React.ReactNode { + return + + + ; + } + + protected onChange(evt: React.ChangeEvent) { + const [grp, brd] = evt.target.value.split("::"); + + const grpidx = parseInt(grp, 10); + const brdidx = parseInt(brd, 10); + + const board = this.availableBoards[grpidx].boards[brdidx]; + this.onSelect(board); + } + + protected onSearchChange(evt: React.ChangeEvent) { + this.searchTerm = evt.target.value; + this.search(); + } + + protected async search() { + const { items } = await this.boardsService.search({query: this.searchTerm }); + this.availableBoards = items.map(pkg => { + const result: BoardGroup = { + name: pkg.name, + boards: pkg.boards.filter(b => b.name.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase())) + } + return result; + }).filter(grp => !!grp.boards).sort((a, b) => { + if (a.name < b.name) return -1; + if (a.name === b.name) return 0; + return 1; + }); + + this.render(); + } + +} + +export class SelectBoardDialog extends AbstractDialog { + protected result: Board; + protected readonly contentRenderer: DialogContentRenderer; + + constructor(boardsService: BoardsService) { + super({ title: 'Select other board' }); + + this.contentNode.classList.add(SelectBoardDialog.Styles.DIALOG_CLASS); + this.contentRenderer = new DialogContentRenderer(boardsService, b => this.result = b); + this.contentRenderer.render(); + this.contentNode.appendChild(this.contentRenderer.host); + + this.appendCloseButton(); + this.appendAcceptButton("Select"); + } + + get value(): Board { + return this.result; + } + + onUpdateRequest(msg: Message) { + super.onUpdateRequest(msg); + this.contentRenderer.render(); + } + + dispose() { + this.contentRenderer.dispose(); + super.dispose(); + } + +} + +export namespace SelectBoardDialog { + export namespace Styles { + export const DIALOG_CLASS = "select-board-dialog"; + export const SELECTOR_CLASS = "selector"; + } +} diff --git a/arduino-ide-extension/src/browser/style/index.css b/arduino-ide-extension/src/browser/style/index.css index 89d6bb76..e965dec7 100644 --- a/arduino-ide-extension/src/browser/style/index.css +++ b/arduino-ide-extension/src/browser/style/index.css @@ -1 +1,2 @@ -@import './list-widget.css'; \ No newline at end of file +@import './list-widget.css'; +@import './select-board-dialog.css'; \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/style/select-board-dialog.css b/arduino-ide-extension/src/browser/style/select-board-dialog.css new file mode 100644 index 00000000..1e3004e8 --- /dev/null +++ b/arduino-ide-extension/src/browser/style/select-board-dialog.css @@ -0,0 +1,13 @@ + +.select-board-dialog { + width: 600px; +} + +.select-board-dialog input { + width: calc(100% - 8px); + margin-bottom: 5px; +} + +.select-board-dialog select { + width: 100%; +} \ No newline at end of file diff --git a/arduino-ide-extension/src/common/protocol/boards-service.ts b/arduino-ide-extension/src/common/protocol/boards-service.ts index efd89948..16654df1 100644 --- a/arduino-ide-extension/src/common/protocol/boards-service.ts +++ b/arduino-ide-extension/src/common/protocol/boards-service.ts @@ -3,24 +3,25 @@ import { ArduinoComponent } from "./arduino-component"; export const BoardsServicePath = '/services/boards-service'; export const BoardsService = Symbol('BoardsService'); export interface BoardsService { - getAttachedBoards(): Promise<{ boards: AttachedBoard[] }>; - selectBoard(board: AttachedBoard): Promise; - getSelectBoard(): Promise; + getAttachedBoards(): Promise<{ boards: Board[] }>; + selectBoard(board: Board): Promise; + getSelectBoard(): Promise; - search(options: { query?: string }): Promise<{ items: Board[] }>; - install(board: Board): Promise; + search(options: { query?: string }): Promise<{ items: BoardPackage[] }>; + install(item: BoardPackage): Promise; } -export interface Board extends ArduinoComponent { +export interface BoardPackage extends ArduinoComponent { id: string; + boards: Board[]; } -export interface AttachedBoard { +export interface Board { name: string fqbn?: string } -export interface AttachedSerialBoard extends AttachedBoard { +export interface AttachedSerialBoard extends Board { port: string; serialNumber: string; productID: string; @@ -28,7 +29,7 @@ export interface AttachedSerialBoard extends AttachedBoard { } export namespace AttachedSerialBoard { - export function is(b: AttachedBoard): b is AttachedSerialBoard { + export function is(b: Board): b is AttachedSerialBoard { return 'port' in b && 'serialNumber' in b && 'productID' in b @@ -36,14 +37,14 @@ export namespace AttachedSerialBoard { } } -export interface AttachedNetworkBoard extends AttachedBoard { +export interface AttachedNetworkBoard extends Board { info: string; address: string; port: number; } export namespace AttachedNetworkBoard { - export function is(b: AttachedBoard): b is AttachedNetworkBoard { + export function is(b: Board): b is AttachedNetworkBoard { return 'name' in b && 'info' in b && 'address' in b diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index 0fcea9b9..29a646d4 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -1,5 +1,5 @@ import { injectable, inject } from 'inversify'; -import { BoardsService, Board, AttachedBoard, AttachedSerialBoard, AttachedNetworkBoard } from '../common/protocol/boards-service'; +import { BoardsService, AttachedSerialBoard, AttachedNetworkBoard, BoardPackage, Board } from '../common/protocol/boards-service'; import { PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq, PlatformListResp } from './cli-protocol/core_pb'; import { CoreClientProvider } from './core-client-provider'; import { BoardListReq, BoardListResp } from './cli-protocol/board_pb'; @@ -10,16 +10,16 @@ export class BoardsServiceImpl implements BoardsService { @inject(CoreClientProvider) protected readonly coreClientProvider: CoreClientProvider; - protected selectedBoard: AttachedBoard | undefined; + protected selectedBoard: Board | undefined; - public async getAttachedBoards(): Promise<{ boards: AttachedBoard[] }> { + public async getAttachedBoards(): Promise<{ boards: Board[] }> { const { client, instance } = await this.coreClientProvider.getClient(); const req = new BoardListReq(); req.setInstance(instance); const resp = await new Promise((resolve, reject) => client.boardList(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp))); - const serialBoards: AttachedBoard[] = resp.getSerialList().map(b => { + const serialBoards: Board[] = resp.getSerialList().map(b => { name: b.getName() || "unknown", fqbn: b.getFqbn(), port: b.getPort(), @@ -27,7 +27,7 @@ export class BoardsServiceImpl implements BoardsService { productID: b.getProductid(), vendorID: b.getVendorid() }); - const networkBoards: AttachedBoard[] = resp.getNetworkList().map(b => { + const networkBoards: Board[] = resp.getNetworkList().map(b => { name: b.getName(), fqbn: b.getFqbn(), address: b.getAddress(), @@ -38,15 +38,15 @@ export class BoardsServiceImpl implements BoardsService { return { boards: serialBoards.concat(networkBoards) }; } - async selectBoard(board: AttachedBoard): Promise { + async selectBoard(board: Board): Promise { this.selectedBoard = board; } - async getSelectBoard(): Promise { + async getSelectBoard(): Promise { return this.selectedBoard; } - async search(options: { query?: string }): Promise<{ items: Board[] }> { + async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> { const { client, instance } = await this.coreClientProvider.getClient(); const installedPlatformsReq = new PlatformListReq(); @@ -55,7 +55,6 @@ export class BoardsServiceImpl implements BoardsService { client.platformList(installedPlatformsReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)) ); const installedPlatforms = installedPlatformsResp.getInstalledPlatformList(); - console.info("Installed platforms", installedPlatforms); const req = new PlatformSearchReq(); req.setSearchArgs(options.query || ""); @@ -69,15 +68,16 @@ export class BoardsServiceImpl implements BoardsService { installedVersion = matchingPlatform.getInstalled(); } - const result: Board = { + const result: BoardPackage = { id: item.getId(), name: item.getName(), author: item.getAuthor(), availableVersions: [ item.getVersion() ], - description: item.getParagragh(), + description: item.getBoardsList().map(b => b.getName()).join(", "), installable: true, - summary: item.getSentence(), + summary: "Boards included in this package:", installedVersion, + boards: item.getBoardsList().map(b => { name: b.getName(), fqbn: b.getFqbn() }), } return result; }); @@ -85,18 +85,18 @@ export class BoardsServiceImpl implements BoardsService { return { items }; } - async install(board: Board): Promise { + async install(pkg: BoardPackage): Promise { const { client, instance } = await this.coreClientProvider.getClient(); - const [ platform, boardName ] = board.id.split(":"); + const [ platform, boardName ] = pkg.id.split(":"); const req = new PlatformInstallReq(); req.setInstance(instance); req.setArchitecture(boardName); req.setPlatformPackage(platform); - req.setVersion(board.availableVersions[0]); + req.setVersion(pkg.availableVersions[0]); - console.info("Starting board installation", board); + console.info("Starting board installation", pkg); const resp = client.platformInstall(req); resp.on('data', (r: PlatformInstallResp) => { const prog = r.getProgress(); @@ -108,7 +108,7 @@ export class BoardsServiceImpl implements BoardsService { resp.on('end', resolve); resp.on('error', reject); }); - console.info("Board installation done", board); + console.info("Board installation done", pkg); } } diff --git a/arduino-ide-extension/src/node/cli-protocol/core_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/core_pb.d.ts index 21f57f15..73402bdd 100644 --- a/arduino-ide-extension/src/node/cli-protocol/core_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/core_pb.d.ts @@ -320,11 +320,10 @@ export class SearchOutput extends jspb.Message { getAuthor(): string; setAuthor(value: string): void; - getSentence(): string; - setSentence(value: string): void; - - getParagragh(): string; - setParagragh(value: string): void; + clearBoardsList(): void; + getBoardsList(): Array; + setBoardsList(value: Array): void; + addBoards(value?: SearchOutputBoard, index?: number): SearchOutputBoard; serializeBinary(): Uint8Array; @@ -343,8 +342,32 @@ export namespace SearchOutput { version: string, name: string, author: string, - sentence: string, - paragragh: string, + boardsList: Array, + } +} + +export class SearchOutputBoard extends jspb.Message { + getName(): string; + setName(value: string): void; + + getFqbn(): string; + setFqbn(value: string): void; + + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): SearchOutputBoard.AsObject; + static toObject(includeInstance: boolean, msg: SearchOutputBoard): SearchOutputBoard.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: SearchOutputBoard, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): SearchOutputBoard; + static deserializeBinaryFromReader(message: SearchOutputBoard, reader: jspb.BinaryReader): SearchOutputBoard; +} + +export namespace SearchOutputBoard { + export type AsObject = { + name: string, + fqbn: string, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/core_pb.js b/arduino-ide-extension/src/node/cli-protocol/core_pb.js index 83af6806..a34fb41e 100644 --- a/arduino-ide-extension/src/node/cli-protocol/core_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/core_pb.js @@ -27,6 +27,7 @@ goog.exportSymbol('proto.arduino.PlatformUninstallResp', null, global); goog.exportSymbol('proto.arduino.PlatformUpgradeReq', null, global); goog.exportSymbol('proto.arduino.PlatformUpgradeResp', null, global); goog.exportSymbol('proto.arduino.SearchOutput', null, global); +goog.exportSymbol('proto.arduino.SearchOutputBoard', null, global); /** * Generated by JsPbCodeGenerator. @@ -2050,12 +2051,19 @@ proto.arduino.PlatformSearchResp.prototype.clearSearchOutputList = function() { * @constructor */ proto.arduino.SearchOutput = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); + jspb.Message.initialize(this, opt_data, 0, -1, proto.arduino.SearchOutput.repeatedFields_, null); }; goog.inherits(proto.arduino.SearchOutput, jspb.Message); if (goog.DEBUG && !COMPILED) { proto.arduino.SearchOutput.displayName = 'proto.arduino.SearchOutput'; } +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.arduino.SearchOutput.repeatedFields_ = [5]; + if (jspb.Message.GENERATE_TO_OBJECT) { @@ -2089,8 +2097,8 @@ proto.arduino.SearchOutput.toObject = function(includeInstance, msg) { version: jspb.Message.getFieldWithDefault(msg, 2, ""), name: jspb.Message.getFieldWithDefault(msg, 3, ""), author: jspb.Message.getFieldWithDefault(msg, 4, ""), - sentence: jspb.Message.getFieldWithDefault(msg, 5, ""), - paragragh: jspb.Message.getFieldWithDefault(msg, 6, "") + boardsList: jspb.Message.toObjectList(msg.getBoardsList(), + proto.arduino.SearchOutputBoard.toObject, includeInstance) }; if (includeInstance) { @@ -2144,12 +2152,9 @@ proto.arduino.SearchOutput.deserializeBinaryFromReader = function(msg, reader) { msg.setAuthor(value); break; case 5: - var value = /** @type {string} */ (reader.readString()); - msg.setSentence(value); - break; - case 6: - var value = /** @type {string} */ (reader.readString()); - msg.setParagragh(value); + var value = new proto.arduino.SearchOutputBoard; + reader.readMessage(value,proto.arduino.SearchOutputBoard.deserializeBinaryFromReader); + msg.addBoards(value); break; default: reader.skipField(); @@ -2208,18 +2213,12 @@ proto.arduino.SearchOutput.serializeBinaryToWriter = function(message, writer) { f ); } - f = message.getSentence(); + f = message.getBoardsList(); if (f.length > 0) { - writer.writeString( + writer.writeRepeatedMessage( 5, - f - ); - } - f = message.getParagragh(); - if (f.length > 0) { - writer.writeString( - 6, - f + f, + proto.arduino.SearchOutputBoard.serializeBinaryToWriter ); } }; @@ -2286,32 +2285,202 @@ proto.arduino.SearchOutput.prototype.setAuthor = function(value) { /** - * optional string Sentence = 5; - * @return {string} + * repeated SearchOutputBoard Boards = 5; + * @return {!Array} */ -proto.arduino.SearchOutput.prototype.getSentence = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); +proto.arduino.SearchOutput.prototype.getBoardsList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.arduino.SearchOutputBoard, 5)); }; -/** @param {string} value */ -proto.arduino.SearchOutput.prototype.setSentence = function(value) { - jspb.Message.setProto3StringField(this, 5, value); +/** @param {!Array} value */ +proto.arduino.SearchOutput.prototype.setBoardsList = function(value) { + jspb.Message.setRepeatedWrapperField(this, 5, value); }; /** - * optional string Paragragh = 6; + * @param {!proto.arduino.SearchOutputBoard=} opt_value + * @param {number=} opt_index + * @return {!proto.arduino.SearchOutputBoard} + */ +proto.arduino.SearchOutput.prototype.addBoards = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 5, opt_value, proto.arduino.SearchOutputBoard, opt_index); +}; + + +proto.arduino.SearchOutput.prototype.clearBoardsList = function() { + this.setBoardsList([]); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.arduino.SearchOutputBoard = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.arduino.SearchOutputBoard, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.arduino.SearchOutputBoard.displayName = 'proto.arduino.SearchOutputBoard'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.arduino.SearchOutputBoard.prototype.toObject = function(opt_includeInstance) { + return proto.arduino.SearchOutputBoard.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.arduino.SearchOutputBoard} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.arduino.SearchOutputBoard.toObject = function(includeInstance, msg) { + var f, obj = { + name: jspb.Message.getFieldWithDefault(msg, 1, ""), + fqbn: jspb.Message.getFieldWithDefault(msg, 2, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.arduino.SearchOutputBoard} + */ +proto.arduino.SearchOutputBoard.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.arduino.SearchOutputBoard; + return proto.arduino.SearchOutputBoard.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.arduino.SearchOutputBoard} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.arduino.SearchOutputBoard} + */ +proto.arduino.SearchOutputBoard.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setFqbn(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.arduino.SearchOutputBoard.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.arduino.SearchOutputBoard.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.arduino.SearchOutputBoard} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.arduino.SearchOutputBoard.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getName(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getFqbn(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } +}; + + +/** + * optional string name = 1; * @return {string} */ -proto.arduino.SearchOutput.prototype.getParagragh = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); +proto.arduino.SearchOutputBoard.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); }; /** @param {string} value */ -proto.arduino.SearchOutput.prototype.setParagragh = function(value) { - jspb.Message.setProto3StringField(this, 6, value); +proto.arduino.SearchOutputBoard.prototype.setName = function(value) { + jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string fqbn = 2; + * @return {string} + */ +proto.arduino.SearchOutputBoard.prototype.getFqbn = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** @param {string} value */ +proto.arduino.SearchOutputBoard.prototype.setFqbn = function(value) { + jspb.Message.setProto3StringField(this, 2, value); }; diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index 0c8ffa0f..f444a2f5 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -2,7 +2,7 @@ import { inject, injectable } from 'inversify'; import { FileSystem } from '@theia/filesystem/lib/common/filesystem'; import { CoreService } from '../common/protocol/core-service'; import { CompileReq, CompileResp } from './cli-protocol/compile_pb'; -import { BoardsService, AttachedSerialBoard } from '../common/protocol/boards-service'; +import { BoardsService, AttachedSerialBoard, AttachedNetworkBoard } from '../common/protocol/boards-service'; import { CoreClientProvider } from './core-client-provider'; import * as path from 'path'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; @@ -51,17 +51,25 @@ export class CoreServiceImpl implements CoreService { compilerReq.setQuiet(false); const result = client.compile(compilerReq); - return new Promise((resolve, reject) => { - result.on('data', (cr: CompileResp) => { - this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString()); - console.error(cr.getErrStream().toString()); + try { + await new Promise((resolve, reject) => { + result.on('data', (cr: CompileResp) => { + this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString()); + this.toolOutputService.publishNewOutput("compile error", new Buffer(cr.getErrStream_asU8()).toString()); + }); + result.on('error', error => reject(error)); + result.on('end', () => resolve()); }); - result.on('error', error => reject(error)); - result.on('end', () => resolve()); - }); + this.toolOutputService.publishNewOutput("compile", "Compilation complete\n"); + } catch (e) { + this.toolOutputService.publishNewOutput("compile error", `Compilation error: ${e}\n`); + throw e; + } } async upload(options: CoreService.Upload.Options): Promise { + await this.compile({uri: options.uri}); + console.log('upload', options); const { uri } = options; const sketchFilePath = await this.fileSystem.getFsPath(options.uri); @@ -86,18 +94,27 @@ export class CoreServiceImpl implements CoreService { req.setFqbn(currentBoard.fqbn); if (AttachedSerialBoard.is(currentBoard)) { req.setPort(currentBoard.port); - } else { + } else if (AttachedNetworkBoard.is(currentBoard)) { throw new Error("can only upload to serial boards"); + } else { + throw new Error("board is not attached"); } const result = client.upload(req); - return new Promise((resolve, reject) => { - result.on('data', (cr: UploadResp) => { - this.toolOutputService.publishNewOutput("upload", new Buffer(cr.getOutStream_asU8()).toString()); - this.toolOutputService.publishNewOutput("upload error", new Buffer(cr.getErrStream_asU8()).toString()); + + try { + await new Promise((resolve, reject) => { + result.on('data', (cr: UploadResp) => { + this.toolOutputService.publishNewOutput("upload", new Buffer(cr.getOutStream_asU8()).toString()); + this.toolOutputService.publishNewOutput("upload error", new Buffer(cr.getErrStream_asU8()).toString()); + }); + result.on('error', error => reject(error)); + result.on('end', () => resolve()); }); - result.on('error', error => reject(error)); - result.on('end', () => resolve()); - }); + this.toolOutputService.publishNewOutput("upload", "Upload complete\n"); + } catch (e) { + this.toolOutputService.publishNewOutput("upload error", `Uplaod error: ${e}\n`); + throw e; + } } } diff --git a/arduino-ide-extension/src/node/tool-output-service-impl.ts b/arduino-ide-extension/src/node/tool-output-service-impl.ts index f81eb447..9aca7dd4 100644 --- a/arduino-ide-extension/src/node/tool-output-service-impl.ts +++ b/arduino-ide-extension/src/node/tool-output-service-impl.ts @@ -6,6 +6,10 @@ export class ToolOutputServiceServerImpl implements ToolOutputServiceServer { protected clients: ToolOutputServiceClient[] = []; publishNewOutput(tool: string, chunk: string): void { + if (!chunk) { + return; + } + this.clients.forEach(c => c.onNewOutput(tool, chunk)); }