Rework listing of discovered ports (#614)

* Removed Protocol type

* Reworked function that groups ports by protocol

* Remove useless protocol check in Port sameAs function

* Reworked port selection menu ordering

Now ports are shown in this order:
1. Serial with recognized boards
2. Serial with unrecognized boards
3. Network with recognized boards
4. Network with unrecognized boards
5. Other protocols with recognized boards
6. Other protocols with unrecognized boards

* Fix ports shown multiple times in menu

* Reworked board selection dropdown ordering

Ordering is now:
1. Serial with recognized boards
2. Serial with guessed boards
3. Serial with incomplete boards
4. Network with recognized boards
5. Other protocols with recognized boards

* Localize some strings

* Fix bug selecting board in boards selector dropdown

* Reworked board selection dialog ordering

* Fix Tools > Port menu not refreshing

* Move Select other board button to bottom of Board selector dropdown and change its style

* Updated arduino-cli to 0.20.0 and generated protocol files
This commit is contained in:
Silvano Cerza
2021-11-24 15:15:40 +01:00
committed by GitHub
parent 20f7712129
commit 74bfdc4c56
30 changed files with 3035 additions and 417 deletions

View File

@@ -1,4 +1,3 @@
import { isWindows, isOSX } from '@theia/core/lib/common/os';
import { naturalCompare } from './../utils';
import { Searchable } from './searchable';
import { Installable } from './installable';
@@ -6,26 +5,18 @@ import { ArduinoComponent } from './arduino-component';
export type AvailablePorts = Record<string, [Port, Array<Board>]>;
export namespace AvailablePorts {
export function groupByProtocol(availablePorts: AvailablePorts): {
serial: AvailablePorts;
network: AvailablePorts;
unknown: AvailablePorts;
} {
const serial: AvailablePorts = {};
const network: AvailablePorts = {};
const unknown: AvailablePorts = {};
for (const key of Object.keys(availablePorts)) {
const [port, boards] = availablePorts[key];
const { protocol } = port;
if (protocol === 'serial') {
serial[key] = [port, boards];
} else if (protocol === 'network') {
network[key] = [port, boards];
} else {
unknown[key] = [port, boards];
export function byProtocol(availablePorts: AvailablePorts): Map<string, AvailablePorts> {
const grouped = new Map<string, AvailablePorts>();
for (const address of Object.keys(availablePorts)) {
const [port, boards] = availablePorts[address];
let ports = grouped.get(port.protocol);
if (!ports) {
ports = {} as AvailablePorts;
}
ports[address] = [port, boards];
grouped.set(port.protocol, ports);
}
return { serial, network, unknown };
return grouped;
}
}
@@ -134,7 +125,7 @@ export const BoardsServicePath = '/services/boards-service';
export const BoardsService = Symbol('BoardsService');
export interface BoardsService
extends Installable<BoardsPackage>,
Searchable<BoardsPackage> {
Searchable<BoardsPackage> {
/**
* Deprecated. `getState` should be used to correctly map a board with a port.
* @deprecated
@@ -156,26 +147,13 @@ export interface BoardsService
export interface Port {
readonly address: string;
readonly protocol: Port.Protocol;
readonly protocol: string;
/**
* Optional label for the protocol. For example: `Serial Port (USB)`.
*/
readonly label?: string;
}
export namespace Port {
export type Protocol = 'serial' | 'network' | 'unknown';
export namespace Protocol {
export function toProtocol(protocol: string | undefined): Protocol {
if (protocol === 'serial') {
return 'serial';
} else if (protocol === 'network') {
return 'network';
} else {
return 'unknown';
}
}
}
export function is(arg: any): arg is Port {
return (
!!arg &&
@@ -197,25 +175,20 @@ export namespace Port {
}
export function compare(left: Port, right: Port): number {
// Board ports have higher priorities, they come first.
if (isBoardPort(left) && !isBoardPort(right)) {
// Ports must be sorted in this order:
// 1. Serial
// 2. Network
// 3. Other protocols
if (left.protocol === "serial" && right.protocol !== "serial") {
return -1;
}
if (!isBoardPort(left) && isBoardPort(right)) {
} else if (left.protocol !== "serial" && right.protocol === "serial") {
return 1;
} else if (left.protocol === "network" && right.protocol !== "network") {
return -1;
} else if (left.protocol !== "network" && right.protocol === "network") {
return 1;
}
let result = naturalCompare(
left.protocol.toLocaleLowerCase(),
right.protocol.toLocaleLowerCase()
);
if (result !== 0) {
return result;
}
result = naturalCompare(left.address, right.address);
if (result !== 0) {
return result;
}
return naturalCompare(left.label || '', right.label || '');
return naturalCompare(left.address!, right.address!);
}
export function equals(
@@ -232,78 +205,14 @@ export namespace Port {
return left === right;
}
// Based on: https://github.com/arduino/Arduino/blob/93581b03d723e55c60caedb4729ffc6ea808fe78/arduino-core/src/processing/app/SerialPortList.java#L48-L74
export function isBoardPort(port: Port): boolean {
const address = port.address.toLocaleLowerCase();
if (isWindows) {
// `COM1` seems to be the default serial port on Windows.
return address !== 'COM1'.toLocaleLowerCase();
}
// On macOS and Linux, the port should start with `/dev/`.
if (!address.startsWith('/dev/')) {
return false;
}
if (isOSX) {
// Example: `/dev/cu.usbmodem14401`
if (/(tty|cu)\..*/i.test(address.substring('/dev/'.length))) {
return [
'/dev/cu.MALS',
'/dev/cu.SOC',
'/dev/cu.Bluetooth-Incoming-Port',
]
.map((a) => a.toLocaleLowerCase())
.every((a) => a !== address);
}
}
// Example: `/dev/ttyACM0`
if (
/(ttyS|ttyUSB|ttyACM|ttyAMA|rfcomm|ttyO)[0-9]{1,3}/i.test(
address.substring('/dev/'.length)
)
) {
// Default ports were `/dev/ttyS0` -> `/dev/ttyS31` on Ubuntu 16.04.2.
if (address.startsWith('/dev/ttyS')) {
const index = Number.parseInt(
address.substring('/dev/ttyS'.length),
10
);
if (!Number.isNaN(index) && 0 <= index && 31 >= index) {
return false;
}
}
return true;
}
return false;
}
export function sameAs(
left: Port | undefined,
right: Port | string | undefined
) {
if (left && right) {
if (left.protocol !== 'serial') {
console.log(
`Unexpected protocol for 'left' port: ${JSON.stringify(
left
)}. Ignoring 'protocol', comparing 'addresses' with ${JSON.stringify(
right
)}.`
);
}
if (typeof right === 'string') {
return left.address === right;
}
if (right.protocol !== 'serial') {
console.log(
`Unexpected protocol for 'right' port: ${JSON.stringify(
right
)}. Ignoring 'protocol', comparing 'addresses' with ${JSON.stringify(
left
)}.`
);
}
return left.address === right.address;
}
return false;