Skip to content

Commit 2263d9a

Browse files
committed
Merge remote-tracking branch 'origin/main' into theia-1.19
# Conflicts: # arduino-ide-extension/src/browser/boards/boards-config.tsx
2 parents 38989cb + 74bfdc4 commit 2263d9a

File tree

8 files changed

+408
-395
lines changed

8 files changed

+408
-395
lines changed

arduino-ide-extension/src/browser/boards/boards-config.tsx

+64-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {
1010
BoardWithPackage,
1111
} from '../../common/protocol/boards-service';
1212
import { NotificationCenter } from '../notification-center';
13-
import { BoardsServiceProvider } from './boards-service-provider';
13+
import {
14+
AvailableBoard,
15+
BoardsServiceProvider,
16+
} from './boards-service-provider';
17+
import { naturalCompare } from '../../common/utils';
1418
import { nls } from '@theia/core/lib/common';
1519

1620
export namespace BoardsConfig {
@@ -184,11 +188,50 @@ export class BoardsConfig extends React.Component<
184188
.filter(notEmpty);
185189
}
186190

191+
protected get availableBoards(): AvailableBoard[] {
192+
return this.props.boardsServiceProvider.availableBoards;
193+
}
194+
187195
protected queryPorts = async (
188196
availablePorts: MaybePromise<Port[]> = this.availablePorts
189197
) => {
190-
const ports = await availablePorts;
191-
return { knownPorts: ports.sort(Port.compare) };
198+
// Available ports must be sorted in this order:
199+
// 1. Serial with recognized boards
200+
// 2. Serial with guessed boards
201+
// 3. Serial with incomplete boards
202+
// 4. Network with recognized boards
203+
// 5. Other protocols with recognized boards
204+
const ports = (await availablePorts).sort((left: Port, right: Port) => {
205+
if (left.protocol === 'serial' && right.protocol !== 'serial') {
206+
return -1;
207+
} else if (left.protocol !== 'serial' && right.protocol === 'serial') {
208+
return 1;
209+
} else if (left.protocol === 'network' && right.protocol !== 'network') {
210+
return -1;
211+
} else if (left.protocol !== 'network' && right.protocol === 'network') {
212+
return 1;
213+
} else if (left.protocol === right.protocol) {
214+
// We show ports, including those that have guessed
215+
// or unrecognized boards, so we must sort those too.
216+
const leftBoard = this.availableBoards.find((board) =>
217+
Port.sameAs(board.port, left)
218+
);
219+
const rightBoard = this.availableBoards.find((board) =>
220+
Port.sameAs(board.port, right)
221+
);
222+
if (leftBoard && !rightBoard) {
223+
return -1;
224+
} else if (!leftBoard && rightBoard) {
225+
return 1;
226+
} else if (leftBoard?.state! < rightBoard?.state!) {
227+
return -1;
228+
} else if (leftBoard?.state! > rightBoard?.state!) {
229+
return 1;
230+
}
231+
}
232+
return naturalCompare(left.address, right.address);
233+
});
234+
return { knownPorts: ports };
192235
};
193236

194237
protected toggleFilterPorts = () => {
@@ -281,8 +324,24 @@ export class BoardsConfig extends React.Component<
281324
}
282325

283326
protected renderPorts(): React.ReactNode {
284-
const filter = this.state.showAllPorts ? () => true : Port.isBoardPort;
285-
const ports = this.state.knownPorts.filter(filter);
327+
let ports = [] as Port[];
328+
if (this.state.showAllPorts) {
329+
ports = this.state.knownPorts;
330+
} else {
331+
ports = this.state.knownPorts.filter((port) => {
332+
if (port.protocol === 'serial') {
333+
return true;
334+
}
335+
// All other ports with different protocol are
336+
// only shown if there is a recognized board
337+
// connected
338+
for (const board of this.availableBoards) {
339+
if (board.port?.address === port.address) {
340+
return true;
341+
}
342+
}
343+
});
344+
}
286345
return !ports.length ? (
287346
<div className="loading noselect">No ports discovered</div>
288347
) : (

arduino-ide-extension/src/browser/boards/boards-service-provider.ts

+90-91
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
4242
protected readonly onAvailableBoardsChangedEmitter = new Emitter<
4343
AvailableBoard[]
4444
>();
45+
protected readonly onAvailablePortsChangedEmitter = new Emitter<Port[]>();
4546

4647
/**
4748
* Used for the auto-reconnecting. Sometimes, the attached board gets disconnected after uploading something to it.
@@ -67,8 +68,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
6768
* This event is also emitted when the board package for the currently selected board was uninstalled.
6869
*/
6970
readonly onBoardsConfigChanged = this.onBoardsConfigChangedEmitter.event;
70-
readonly onAvailableBoardsChanged =
71-
this.onAvailableBoardsChangedEmitter.event;
71+
readonly onAvailableBoardsChanged = this.onAvailableBoardsChangedEmitter.event;
72+
readonly onAvailablePortsChanged = this.onAvailablePortsChangedEmitter.event;
7273

7374
onStart(): void {
7475
this.notificationCenter.onAttachedBoardsChanged(
@@ -88,6 +89,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
8889
]).then(([attachedBoards, availablePorts]) => {
8990
this._attachedBoards = attachedBoards;
9091
this._availablePorts = availablePorts;
92+
this.onAvailablePortsChangedEmitter.fire(this._availablePorts);
9193
this.reconcileAvailableBoards().then(() => this.tryReconnect());
9294
});
9395
}
@@ -102,6 +104,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
102104
}
103105
this._attachedBoards = event.newState.boards;
104106
this._availablePorts = event.newState.ports;
107+
this.onAvailablePortsChangedEmitter.fire(this._availablePorts);
105108
this.reconcileAvailableBoards().then(() => this.tryReconnect());
106109
}
107110

@@ -180,8 +183,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
180183
const selectedAvailableBoard = AvailableBoard.is(selectedBoard)
181184
? selectedBoard
182185
: this._availableBoards.find((availableBoard) =>
183-
Board.sameAs(availableBoard, selectedBoard)
184-
);
186+
Board.sameAs(availableBoard, selectedBoard)
187+
);
185188
if (
186189
selectedAvailableBoard &&
187190
selectedAvailableBoard.selected &&
@@ -358,14 +361,14 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
358361
const timeoutTask =
359362
!!timeout && timeout > 0
360363
? new Promise<void>((_, reject) =>
361-
setTimeout(
362-
() => reject(new Error(`Timeout after ${timeout} ms.`)),
363-
timeout
364-
)
364+
setTimeout(
365+
() => reject(new Error(`Timeout after ${timeout} ms.`)),
366+
timeout
365367
)
368+
)
366369
: new Promise<void>(() => {
367-
/* never */
368-
});
370+
/* never */
371+
});
369372
const waitUntilTask = new Promise<void>((resolve) => {
370373
let candidate = find(what, this.availableBoards);
371374
if (candidate) {
@@ -384,7 +387,6 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
384387
}
385388

386389
protected async reconcileAvailableBoards(): Promise<void> {
387-
const attachedBoards = this._attachedBoards;
388390
const availablePorts = this._availablePorts;
389391
// Unset the port on the user's config, if it is not available anymore.
390392
if (
@@ -402,51 +404,64 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
402404
const boardsConfig = this.boardsConfig;
403405
const currentAvailableBoards = this._availableBoards;
404406
const availableBoards: AvailableBoard[] = [];
405-
const availableBoardPorts = availablePorts.filter(Port.isBoardPort);
406-
const attachedSerialBoards = attachedBoards.filter(({ port }) => !!port);
407+
const attachedBoards = this._attachedBoards.filter(({ port }) => !!port);
408+
const availableBoardPorts = availablePorts.filter((port) => {
409+
if (port.protocol === "serial") {
410+
// We always show all serial ports, even if there
411+
// is no recognized board connected to it
412+
return true;
413+
}
414+
415+
// All other ports with different protocol are
416+
// only shown if there is a recognized board
417+
// connected
418+
for (const board of attachedBoards) {
419+
if (board.port?.address === port.address) {
420+
return true;
421+
}
422+
}
423+
return false;
424+
});
407425

408426
for (const boardPort of availableBoardPorts) {
409-
let state = AvailableBoard.State.incomplete; // Initial pessimism.
410-
let board = attachedSerialBoards.find(({ port }) =>
411-
Port.sameAs(boardPort, port)
412-
);
427+
let board = attachedBoards.find(({ port }) => Port.sameAs(boardPort, port));
428+
const lastSelectedBoard = await this.getLastSelectedBoardOnPort(boardPort);
429+
430+
let availableBoard = {} as AvailableBoard;
413431
if (board) {
414-
state = AvailableBoard.State.recognized;
415-
} else {
432+
availableBoard = {
433+
...board,
434+
state: AvailableBoard.State.recognized,
435+
selected: BoardsConfig.Config.sameAs(boardsConfig, board),
436+
port: boardPort,
437+
};
438+
} else if (lastSelectedBoard) {
416439
// If the selected board is not recognized because it is a 3rd party board: https://github.com/arduino/arduino-cli/issues/623
417440
// We still want to show it without the red X in the boards toolbar: https://github.com/arduino/arduino-pro-ide/issues/198#issuecomment-599355836
418-
const lastSelectedBoard = await this.getLastSelectedBoardOnPort(
419-
boardPort
420-
);
421-
if (lastSelectedBoard) {
422-
board = {
423-
...lastSelectedBoard,
424-
port: boardPort,
425-
};
426-
state = AvailableBoard.State.guessed;
427-
}
428-
}
429-
if (!board) {
430-
availableBoards.push({
431-
name: nls.localize('arduino/common/unknown', 'Unknown'),
441+
availableBoard = {
442+
...lastSelectedBoard,
443+
state: AvailableBoard.State.guessed,
444+
selected: BoardsConfig.Config.sameAs(boardsConfig, lastSelectedBoard),
432445
port: boardPort,
433-
state,
434-
});
446+
};
435447
} else {
436-
const selected = BoardsConfig.Config.sameAs(boardsConfig, board);
437-
availableBoards.push({
438-
...board,
439-
state,
440-
selected,
448+
availableBoard = {
449+
name: nls.localize('arduino/common/unknown', 'Unknown'),
441450
port: boardPort,
442-
});
451+
state: AvailableBoard.State.incomplete,
452+
};
443453
}
454+
availableBoards.push(availableBoard);
444455
}
445456

446-
if (
447-
boardsConfig.selectedBoard &&
448-
!availableBoards.some(({ selected }) => selected)
449-
) {
457+
if (boardsConfig.selectedBoard && !availableBoards.some(({ selected }) => selected)) {
458+
// If the selected board has the same port of an unknown board
459+
// that is already in availableBoards we might get a duplicate port.
460+
// So we remove the one already in the array and add the selected one.
461+
const found = availableBoards.findIndex(board => board.port?.address === boardsConfig.selectedPort?.address);
462+
if (found >= 0) {
463+
availableBoards.splice(found, 1);
464+
}
450465
availableBoards.push({
451466
...boardsConfig.selectedBoard,
452467
port: boardsConfig.selectedPort,
@@ -455,28 +470,20 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
455470
});
456471
}
457472

458-
const sortedAvailableBoards = availableBoards.sort(AvailableBoard.compare);
459-
let hasChanged =
460-
sortedAvailableBoards.length !== currentAvailableBoards.length;
461-
for (let i = 0; !hasChanged && i < sortedAvailableBoards.length; i++) {
462-
hasChanged =
463-
AvailableBoard.compare(
464-
sortedAvailableBoards[i],
465-
currentAvailableBoards[i]
466-
) !== 0;
473+
availableBoards.sort(AvailableBoard.compare);
474+
475+
let hasChanged = availableBoards.length !== currentAvailableBoards.length;
476+
for (let i = 0; !hasChanged && i < availableBoards.length; i++) {
477+
const [left, right] = [availableBoards[i], currentAvailableBoards[i]];
478+
hasChanged = !!AvailableBoard.compare(left, right) || left.selected !== right.selected;
467479
}
468480
if (hasChanged) {
469-
this._availableBoards = sortedAvailableBoards;
481+
this._availableBoards = availableBoards;
470482
this.onAvailableBoardsChangedEmitter.fire(this._availableBoards);
471483
}
472484
}
473485

474-
protected async getLastSelectedBoardOnPort(
475-
port: Port | string | undefined
476-
): Promise<Board | undefined> {
477-
if (!port) {
478-
return undefined;
479-
}
486+
protected async getLastSelectedBoardOnPort(port: Port): Promise<Board | undefined> {
480487
const key = this.getLastSelectedBoardOnPortKey(port);
481488
return this.getData<Board>(key);
482489
}
@@ -497,11 +504,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
497504
]);
498505
}
499506

500-
protected getLastSelectedBoardOnPortKey(port: Port | string): string {
501-
// TODO: we lose the port's `protocol` info (`serial`, `network`, etc.) here if the `port` is a `string`.
502-
return `last-selected-board-on-port:${
503-
typeof port === 'string' ? port : Port.toString(port)
504-
}`;
507+
protected getLastSelectedBoardOnPortKey(port: Port): string {
508+
return `last-selected-board-on-port:${Port.toString(port)}`;
505509
}
506510

507511
protected async loadState(): Promise<void> {
@@ -585,35 +589,30 @@ export namespace AvailableBoard {
585589
return !!board.port;
586590
}
587591

592+
// Available boards must be sorted in this order:
593+
// 1. Serial with recognized boards
594+
// 2. Serial with guessed boards
595+
// 3. Serial with incomplete boards
596+
// 4. Network with recognized boards
597+
// 5. Other protocols with recognized boards
588598
export const compare = (left: AvailableBoard, right: AvailableBoard) => {
589-
if (left.selected && !right.selected) {
599+
if (left.port?.protocol === "serial" && right.port?.protocol !== "serial") {
590600
return -1;
591-
}
592-
if (right.selected && !left.selected) {
601+
} else if (left.port?.protocol !== "serial" && right.port?.protocol === "serial") {
593602
return 1;
594-
}
595-
let result = naturalCompare(left.name, right.name);
596-
if (result !== 0) {
597-
return result;
598-
}
599-
if (left.fqbn && right.fqbn) {
600-
result = naturalCompare(left.fqbn, right.fqbn);
601-
if (result !== 0) {
602-
return result;
603-
}
604-
}
605-
if (left.port && right.port) {
606-
result = Port.compare(left.port, right.port);
607-
if (result !== 0) {
608-
return result;
609-
}
610-
}
611-
if (!!left.selected && !right.selected) {
603+
} else if (left.port?.protocol === "network" && right.port?.protocol !== "network") {
612604
return -1;
613-
}
614-
if (!!right.selected && !left.selected) {
605+
} else if (left.port?.protocol !== "network" && right.port?.protocol === "network") {
615606
return 1;
607+
} else if (left.port?.protocol === right.port?.protocol) {
608+
// We show all ports, including those that have guessed
609+
// or unrecognized boards, so we must sort those too.
610+
if (left.state < right.state) {
611+
return -1;
612+
} else if (left.state > right.state) {
613+
return 1;
614+
}
616615
}
617-
return left.state - right.state;
618-
};
616+
return naturalCompare(left.port?.address!, right.port?.address!);
617+
}
619618
}

0 commit comments

Comments
 (0)