Implemented non-attached boards

This commit is contained in:
Christian Weichel 2019-05-08 11:25:52 +02:00
parent d787de3ed9
commit be20365a6b
14 changed files with 472 additions and 110 deletions

View File

@ -12,6 +12,7 @@ import { ConnectedBoards } from './components/connected-boards';
import { CoreService } from '../common/protocol/core-service'; import { CoreService } from '../common/protocol/core-service';
import { WorkspaceServiceExt } from './workspace-service-ext'; import { WorkspaceServiceExt } from './workspace-service-ext';
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service'; import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
import { ConfirmDialog } from '@theia/core/lib/browser';
@injectable() @injectable()
@ -65,6 +66,10 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
isVisible: widget => this.isArduinoEditor(widget), isVisible: widget => this.isArduinoEditor(widget),
isEnabled: widget => this.isArduinoEditor(widget), isEnabled: widget => this.isArduinoEditor(widget),
execute: async widget => { execute: async widget => {
if (widget instanceof EditorWidget) {
await widget.saveable.save();
}
const uri = this.toUri(widget); const uri = this.toUri(widget);
if (uri) { if (uri) {
const result = await this.coreService.compile({ uri: uri.toString() }); const result = await this.coreService.compile({ uri: uri.toString() });
@ -76,10 +81,19 @@ export class ArduinoFrontendContribution extends DefaultFrontendApplicationContr
isVisible: widget => this.isArduinoEditor(widget), isVisible: widget => this.isArduinoEditor(widget),
isEnabled: widget => this.isArduinoEditor(widget), isEnabled: widget => this.isArduinoEditor(widget),
execute: async widget => { execute: async widget => {
if (widget instanceof EditorWidget) {
await widget.saveable.save();
}
const uri = this.toUri(widget); const uri = this.toUri(widget);
if (uri) { if (!uri) {
const result = await this.coreService.upload({ uri: uri.toString() }); return;
console.log('upload result', result); }
try {
await this.coreService.upload({ uri: uri.toString() });
} catch (e) {
new ConfirmDialog({ title: "Error during upload", msg: e.toString(), ok: "Ok" }).open();
} }
} }
}); });

View File

@ -1,7 +1,6 @@
import * as React from 'react'; import * as React from 'react';
// TODO: make this `async`. import { BoardsService, Board } from '../../common/protocol/boards-service';
// import { Async } from 'react-select/lib/Async'; import { SelectBoardDialog } from './select-board-dialog';
import { BoardsService, AttachedBoard } from '../../common/protocol/boards-service';
export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> { export class ConnectedBoards extends React.Component<ConnectedBoards.Props, ConnectedBoards.State> {
static TOOLBAR_ID: 'connected-boards-toolbar'; static TOOLBAR_ID: 'connected-boards-toolbar';
@ -12,23 +11,28 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
} }
render(): React.ReactNode { render(): React.ReactNode {
let label = "no board available";
if (this.state.boardsLoading) {
label = "Loading ...";
} else if (!!this.state.current) {
label = this.state.current.name;
}
let content = []; let content = [];
if (!!this.state.boards) { if (!!this.state.boards && this.state.boards.length > 0) {
content = this.state.boards.map((b, i) => <option value={i} key={i}>{b.name}</option>); content = this.state.boards.map((b, i) => <option value={i} key={i}>{b.name}</option>);
} else { } else {
let label;
if (this.state.boardsLoading) {
label = "Loading ...";
} else {
label = "No board attached";
}
content = [ <option key="loading" value="0">{label}</option> ]; content = [ <option key="loading" value="0">{label}</option> ];
} }
return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}> return <div className={ConnectedBoards.Styles.CONNECTED_BOARDS_CLASS}>
<select disabled={!this.state.boards} onChange={this.onBoardSelect.bind(this)}> <select disabled={!this.state.boards} onChange={this.onBoardSelect.bind(this)} value={this.state.selection}>
<optgroup label="Attached boards">
{ content } { content }
</optgroup>
<optgroup label="_________">
{ !!this.state.otherBoard && <option value="selected-other" key="selected-other">{this.state.otherBoard.name} (not attached)</option> }
<option value="select-other" key="select-other">Select other Board</option>
</optgroup>
</select> </select>
</div>; </div>;
} }
@ -38,26 +42,38 @@ export class ConnectedBoards extends React.Component<ConnectedBoards.Props, Conn
} }
protected async reloadBoards() { protected async reloadBoards() {
this.setState({ boardsLoading: true, boards: undefined, current: undefined }); this.setState({ boardsLoading: true, boards: undefined, selection: undefined });
const { boards } = await this.props.boardsService.getAttachedBoards() const { boards } = await this.props.boardsService.getAttachedBoards()
this.setState({ boards, boardsLoading: false }); this.setState({ boards, boardsLoading: false });
if (boards) { if (boards) {
this.selectBoard(boards[0]); this.setState({ selection: "0" });
await this.props.boardsService.selectBoard(boards[0]);
} }
} }
protected async onBoardSelect(evt: React.ChangeEvent<HTMLSelectElement>) { protected async onBoardSelect(evt: React.ChangeEvent<HTMLSelectElement>) {
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) { if (!selectedBoard) {
return; return;
} }
this.selectBoard(selectedBoard);
await this.props.boardsService.selectBoard(selectedBoard);
this.setState({otherBoard: selectedBoard, selection: "selected-other"});
return;
} }
protected async selectBoard(board: AttachedBoard) { const selectedBoard = (this.state.boards || [])[parseInt(selection, 10)];
await this.props.boardsService.selectBoard(board); if (!selectedBoard) {
this.setState({ current: board }); return;
}
await this.props.boardsService.selectBoard(selectedBoard);
this.setState({selection});
} }
} }
@ -70,8 +86,9 @@ export namespace ConnectedBoards {
export interface State { export interface State {
boardsLoading: boolean; boardsLoading: boolean;
boards?: AttachedBoard[]; boards?: Board[];
current?: AttachedBoard; otherBoard?: Board;
selection?: string;
} }
export namespace Styles { export namespace Styles {

View File

@ -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 <React.Fragment>
<input type="text" placeholder="Search ..." onChange={this.onSearchChange.bind(this)} value={this.searchTerm} />
<select size={10} onChange={this.onChange.bind(this)}>
{ this.availableBoards.map((b, i) => (
<optgroup key={"pkg" + i} label={b.name}>
{ b.boards.map((brd, j) => <option key={j} value={`${i}::${j}`}>{brd.name}</option>) }
</optgroup>
)) }
</select>
</React.Fragment>;
}
protected onChange(evt: React.ChangeEvent<HTMLSelectElement>) {
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<HTMLInputElement>) {
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<Board> {
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";
}
}

View File

@ -1 +1,2 @@
@import './list-widget.css'; @import './list-widget.css';
@import './select-board-dialog.css';

View File

@ -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%;
}

View File

@ -3,24 +3,25 @@ import { ArduinoComponent } from "./arduino-component";
export const BoardsServicePath = '/services/boards-service'; export const BoardsServicePath = '/services/boards-service';
export const BoardsService = Symbol('BoardsService'); export const BoardsService = Symbol('BoardsService');
export interface BoardsService { export interface BoardsService {
getAttachedBoards(): Promise<{ boards: AttachedBoard[] }>; getAttachedBoards(): Promise<{ boards: Board[] }>;
selectBoard(board: AttachedBoard): Promise<void>; selectBoard(board: Board): Promise<void>;
getSelectBoard(): Promise<AttachedBoard | undefined>; getSelectBoard(): Promise<Board | undefined>;
search(options: { query?: string }): Promise<{ items: Board[] }>; search(options: { query?: string }): Promise<{ items: BoardPackage[] }>;
install(board: Board): Promise<void>; install(item: BoardPackage): Promise<void>;
} }
export interface Board extends ArduinoComponent { export interface BoardPackage extends ArduinoComponent {
id: string; id: string;
boards: Board[];
} }
export interface AttachedBoard { export interface Board {
name: string name: string
fqbn?: string fqbn?: string
} }
export interface AttachedSerialBoard extends AttachedBoard { export interface AttachedSerialBoard extends Board {
port: string; port: string;
serialNumber: string; serialNumber: string;
productID: string; productID: string;
@ -28,7 +29,7 @@ export interface AttachedSerialBoard extends AttachedBoard {
} }
export namespace AttachedSerialBoard { export namespace AttachedSerialBoard {
export function is(b: AttachedBoard): b is AttachedSerialBoard { export function is(b: Board): b is AttachedSerialBoard {
return 'port' in b return 'port' in b
&& 'serialNumber' in b && 'serialNumber' in b
&& 'productID' in b && 'productID' in b
@ -36,14 +37,14 @@ export namespace AttachedSerialBoard {
} }
} }
export interface AttachedNetworkBoard extends AttachedBoard { export interface AttachedNetworkBoard extends Board {
info: string; info: string;
address: string; address: string;
port: number; port: number;
} }
export namespace AttachedNetworkBoard { export namespace AttachedNetworkBoard {
export function is(b: AttachedBoard): b is AttachedNetworkBoard { export function is(b: Board): b is AttachedNetworkBoard {
return 'name' in b return 'name' in b
&& 'info' in b && 'info' in b
&& 'address' in b && 'address' in b

View File

@ -1,5 +1,5 @@
import { injectable, inject } from 'inversify'; 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 { PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq, PlatformListResp } from './cli-protocol/core_pb';
import { CoreClientProvider } from './core-client-provider'; import { CoreClientProvider } from './core-client-provider';
import { BoardListReq, BoardListResp } from './cli-protocol/board_pb'; import { BoardListReq, BoardListResp } from './cli-protocol/board_pb';
@ -10,16 +10,16 @@ export class BoardsServiceImpl implements BoardsService {
@inject(CoreClientProvider) @inject(CoreClientProvider)
protected readonly coreClientProvider: 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 { client, instance } = await this.coreClientProvider.getClient();
const req = new BoardListReq(); const req = new BoardListReq();
req.setInstance(instance); req.setInstance(instance);
const resp = await new Promise<BoardListResp>((resolve, reject) => client.boardList(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp))); const resp = await new Promise<BoardListResp>((resolve, reject) => client.boardList(req, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)));
const serialBoards: AttachedBoard[] = resp.getSerialList().map(b => <AttachedSerialBoard>{ const serialBoards: Board[] = resp.getSerialList().map(b => <AttachedSerialBoard>{
name: b.getName() || "unknown", name: b.getName() || "unknown",
fqbn: b.getFqbn(), fqbn: b.getFqbn(),
port: b.getPort(), port: b.getPort(),
@ -27,7 +27,7 @@ export class BoardsServiceImpl implements BoardsService {
productID: b.getProductid(), productID: b.getProductid(),
vendorID: b.getVendorid() vendorID: b.getVendorid()
}); });
const networkBoards: AttachedBoard[] = resp.getNetworkList().map(b => <AttachedNetworkBoard>{ const networkBoards: Board[] = resp.getNetworkList().map(b => <AttachedNetworkBoard>{
name: b.getName(), name: b.getName(),
fqbn: b.getFqbn(), fqbn: b.getFqbn(),
address: b.getAddress(), address: b.getAddress(),
@ -38,15 +38,15 @@ export class BoardsServiceImpl implements BoardsService {
return { boards: serialBoards.concat(networkBoards) }; return { boards: serialBoards.concat(networkBoards) };
} }
async selectBoard(board: AttachedBoard): Promise<void> { async selectBoard(board: Board): Promise<void> {
this.selectedBoard = board; this.selectedBoard = board;
} }
async getSelectBoard(): Promise<AttachedBoard | undefined> { async getSelectBoard(): Promise<Board | undefined> {
return this.selectedBoard; 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 { client, instance } = await this.coreClientProvider.getClient();
const installedPlatformsReq = new PlatformListReq(); const installedPlatformsReq = new PlatformListReq();
@ -55,7 +55,6 @@ export class BoardsServiceImpl implements BoardsService {
client.platformList(installedPlatformsReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)) client.platformList(installedPlatformsReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp))
); );
const installedPlatforms = installedPlatformsResp.getInstalledPlatformList(); const installedPlatforms = installedPlatformsResp.getInstalledPlatformList();
console.info("Installed platforms", installedPlatforms);
const req = new PlatformSearchReq(); const req = new PlatformSearchReq();
req.setSearchArgs(options.query || ""); req.setSearchArgs(options.query || "");
@ -69,15 +68,16 @@ export class BoardsServiceImpl implements BoardsService {
installedVersion = matchingPlatform.getInstalled(); installedVersion = matchingPlatform.getInstalled();
} }
const result: Board = { const result: BoardPackage = {
id: item.getId(), id: item.getId(),
name: item.getName(), name: item.getName(),
author: item.getAuthor(), author: item.getAuthor(),
availableVersions: [ item.getVersion() ], availableVersions: [ item.getVersion() ],
description: item.getParagragh(), description: item.getBoardsList().map(b => b.getName()).join(", "),
installable: true, installable: true,
summary: item.getSentence(), summary: "Boards included in this package:",
installedVersion, installedVersion,
boards: item.getBoardsList().map(b => <Board>{ name: b.getName(), fqbn: b.getFqbn() }),
} }
return result; return result;
}); });
@ -85,18 +85,18 @@ export class BoardsServiceImpl implements BoardsService {
return { items }; return { items };
} }
async install(board: Board): Promise<void> { async install(pkg: BoardPackage): Promise<void> {
const { client, instance } = await this.coreClientProvider.getClient(); const { client, instance } = await this.coreClientProvider.getClient();
const [ platform, boardName ] = board.id.split(":"); const [ platform, boardName ] = pkg.id.split(":");
const req = new PlatformInstallReq(); const req = new PlatformInstallReq();
req.setInstance(instance); req.setInstance(instance);
req.setArchitecture(boardName); req.setArchitecture(boardName);
req.setPlatformPackage(platform); 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); const resp = client.platformInstall(req);
resp.on('data', (r: PlatformInstallResp) => { resp.on('data', (r: PlatformInstallResp) => {
const prog = r.getProgress(); const prog = r.getProgress();
@ -108,7 +108,7 @@ export class BoardsServiceImpl implements BoardsService {
resp.on('end', resolve); resp.on('end', resolve);
resp.on('error', reject); resp.on('error', reject);
}); });
console.info("Board installation done", board); console.info("Board installation done", pkg);
} }
} }

View File

@ -320,11 +320,10 @@ export class SearchOutput extends jspb.Message {
getAuthor(): string; getAuthor(): string;
setAuthor(value: string): void; setAuthor(value: string): void;
getSentence(): string; clearBoardsList(): void;
setSentence(value: string): void; getBoardsList(): Array<SearchOutputBoard>;
setBoardsList(value: Array<SearchOutputBoard>): void;
getParagragh(): string; addBoards(value?: SearchOutputBoard, index?: number): SearchOutputBoard;
setParagragh(value: string): void;
serializeBinary(): Uint8Array; serializeBinary(): Uint8Array;
@ -343,8 +342,32 @@ export namespace SearchOutput {
version: string, version: string,
name: string, name: string,
author: string, author: string,
sentence: string, boardsList: Array<SearchOutputBoard.AsObject>,
paragragh: string, }
}
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<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
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,
} }
} }

View File

@ -27,6 +27,7 @@ goog.exportSymbol('proto.arduino.PlatformUninstallResp', null, global);
goog.exportSymbol('proto.arduino.PlatformUpgradeReq', null, global); goog.exportSymbol('proto.arduino.PlatformUpgradeReq', null, global);
goog.exportSymbol('proto.arduino.PlatformUpgradeResp', null, global); goog.exportSymbol('proto.arduino.PlatformUpgradeResp', null, global);
goog.exportSymbol('proto.arduino.SearchOutput', null, global); goog.exportSymbol('proto.arduino.SearchOutput', null, global);
goog.exportSymbol('proto.arduino.SearchOutputBoard', null, global);
/** /**
* Generated by JsPbCodeGenerator. * Generated by JsPbCodeGenerator.
@ -2050,12 +2051,19 @@ proto.arduino.PlatformSearchResp.prototype.clearSearchOutputList = function() {
* @constructor * @constructor
*/ */
proto.arduino.SearchOutput = function(opt_data) { 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); goog.inherits(proto.arduino.SearchOutput, jspb.Message);
if (goog.DEBUG && !COMPILED) { if (goog.DEBUG && !COMPILED) {
proto.arduino.SearchOutput.displayName = 'proto.arduino.SearchOutput'; proto.arduino.SearchOutput.displayName = 'proto.arduino.SearchOutput';
} }
/**
* List of repeated fields within this message type.
* @private {!Array<number>}
* @const
*/
proto.arduino.SearchOutput.repeatedFields_ = [5];
if (jspb.Message.GENERATE_TO_OBJECT) { if (jspb.Message.GENERATE_TO_OBJECT) {
@ -2089,8 +2097,8 @@ proto.arduino.SearchOutput.toObject = function(includeInstance, msg) {
version: jspb.Message.getFieldWithDefault(msg, 2, ""), version: jspb.Message.getFieldWithDefault(msg, 2, ""),
name: jspb.Message.getFieldWithDefault(msg, 3, ""), name: jspb.Message.getFieldWithDefault(msg, 3, ""),
author: jspb.Message.getFieldWithDefault(msg, 4, ""), author: jspb.Message.getFieldWithDefault(msg, 4, ""),
sentence: jspb.Message.getFieldWithDefault(msg, 5, ""), boardsList: jspb.Message.toObjectList(msg.getBoardsList(),
paragragh: jspb.Message.getFieldWithDefault(msg, 6, "") proto.arduino.SearchOutputBoard.toObject, includeInstance)
}; };
if (includeInstance) { if (includeInstance) {
@ -2144,12 +2152,9 @@ proto.arduino.SearchOutput.deserializeBinaryFromReader = function(msg, reader) {
msg.setAuthor(value); msg.setAuthor(value);
break; break;
case 5: case 5:
var value = /** @type {string} */ (reader.readString()); var value = new proto.arduino.SearchOutputBoard;
msg.setSentence(value); reader.readMessage(value,proto.arduino.SearchOutputBoard.deserializeBinaryFromReader);
break; msg.addBoards(value);
case 6:
var value = /** @type {string} */ (reader.readString());
msg.setParagragh(value);
break; break;
default: default:
reader.skipField(); reader.skipField();
@ -2208,18 +2213,12 @@ proto.arduino.SearchOutput.serializeBinaryToWriter = function(message, writer) {
f f
); );
} }
f = message.getSentence(); f = message.getBoardsList();
if (f.length > 0) { if (f.length > 0) {
writer.writeString( writer.writeRepeatedMessage(
5, 5,
f f,
); proto.arduino.SearchOutputBoard.serializeBinaryToWriter
}
f = message.getParagragh();
if (f.length > 0) {
writer.writeString(
6,
f
); );
} }
}; };
@ -2286,32 +2285,202 @@ proto.arduino.SearchOutput.prototype.setAuthor = function(value) {
/** /**
* optional string Sentence = 5; * repeated SearchOutputBoard Boards = 5;
* @return {string} * @return {!Array<!proto.arduino.SearchOutputBoard>}
*/ */
proto.arduino.SearchOutput.prototype.getSentence = function() { proto.arduino.SearchOutput.prototype.getBoardsList = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); return /** @type{!Array<!proto.arduino.SearchOutputBoard>} */ (
jspb.Message.getRepeatedWrapperField(this, proto.arduino.SearchOutputBoard, 5));
}; };
/** @param {string} value */ /** @param {!Array<!proto.arduino.SearchOutputBoard>} value */
proto.arduino.SearchOutput.prototype.setSentence = function(value) { proto.arduino.SearchOutput.prototype.setBoardsList = function(value) {
jspb.Message.setProto3StringField(this, 5, 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_<name>, 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} * @return {string}
*/ */
proto.arduino.SearchOutput.prototype.getParagragh = function() { proto.arduino.SearchOutputBoard.prototype.getName = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
}; };
/** @param {string} value */ /** @param {string} value */
proto.arduino.SearchOutput.prototype.setParagragh = function(value) { proto.arduino.SearchOutputBoard.prototype.setName = function(value) {
jspb.Message.setProto3StringField(this, 6, 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);
}; };

View File

@ -2,7 +2,7 @@ import { inject, injectable } from 'inversify';
import { FileSystem } from '@theia/filesystem/lib/common/filesystem'; import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
import { CoreService } from '../common/protocol/core-service'; import { CoreService } from '../common/protocol/core-service';
import { CompileReq, CompileResp } from './cli-protocol/compile_pb'; 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 { CoreClientProvider } from './core-client-provider';
import * as path from 'path'; import * as path from 'path';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
@ -51,17 +51,25 @@ export class CoreServiceImpl implements CoreService {
compilerReq.setQuiet(false); compilerReq.setQuiet(false);
const result = client.compile(compilerReq); const result = client.compile(compilerReq);
return new Promise<void>((resolve, reject) => { try {
await new Promise<void>((resolve, reject) => {
result.on('data', (cr: CompileResp) => { result.on('data', (cr: CompileResp) => {
this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString()); this.toolOutputService.publishNewOutput("compile", new Buffer(cr.getOutStream_asU8()).toString());
console.error(cr.getErrStream().toString()); this.toolOutputService.publishNewOutput("compile error", new Buffer(cr.getErrStream_asU8()).toString());
}); });
result.on('error', error => reject(error)); result.on('error', error => reject(error));
result.on('end', () => resolve()); 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<void> { async upload(options: CoreService.Upload.Options): Promise<void> {
await this.compile({uri: options.uri});
console.log('upload', options); console.log('upload', options);
const { uri } = options; const { uri } = options;
const sketchFilePath = await this.fileSystem.getFsPath(options.uri); const sketchFilePath = await this.fileSystem.getFsPath(options.uri);
@ -86,11 +94,15 @@ export class CoreServiceImpl implements CoreService {
req.setFqbn(currentBoard.fqbn); req.setFqbn(currentBoard.fqbn);
if (AttachedSerialBoard.is(currentBoard)) { if (AttachedSerialBoard.is(currentBoard)) {
req.setPort(currentBoard.port); req.setPort(currentBoard.port);
} else { } else if (AttachedNetworkBoard.is(currentBoard)) {
throw new Error("can only upload to serial boards"); throw new Error("can only upload to serial boards");
} else {
throw new Error("board is not attached");
} }
const result = client.upload(req); const result = client.upload(req);
return new Promise<void>((resolve, reject) => {
try {
await new Promise<void>((resolve, reject) => {
result.on('data', (cr: UploadResp) => { result.on('data', (cr: UploadResp) => {
this.toolOutputService.publishNewOutput("upload", new Buffer(cr.getOutStream_asU8()).toString()); this.toolOutputService.publishNewOutput("upload", new Buffer(cr.getOutStream_asU8()).toString());
this.toolOutputService.publishNewOutput("upload error", new Buffer(cr.getErrStream_asU8()).toString()); this.toolOutputService.publishNewOutput("upload error", new Buffer(cr.getErrStream_asU8()).toString());
@ -98,6 +110,11 @@ export class CoreServiceImpl implements CoreService {
result.on('error', error => reject(error)); result.on('error', error => reject(error));
result.on('end', () => resolve()); result.on('end', () => resolve());
}); });
this.toolOutputService.publishNewOutput("upload", "Upload complete\n");
} catch (e) {
this.toolOutputService.publishNewOutput("upload error", `Uplaod error: ${e}\n`);
throw e;
}
} }
} }

View File

@ -6,6 +6,10 @@ export class ToolOutputServiceServerImpl implements ToolOutputServiceServer {
protected clients: ToolOutputServiceClient[] = []; protected clients: ToolOutputServiceClient[] = [];
publishNewOutput(tool: string, chunk: string): void { publishNewOutput(tool: string, chunk: string): void {
if (!chunk) {
return;
}
this.clients.forEach(c => c.onNewOutput(tool, chunk)); this.clients.forEach(c => c.onNewOutput(tool, chunk));
} }