Skip to content

Commit

Permalink
single-source port match logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Akos Kitta committed Jul 25, 2023
1 parent a3382ba commit a92bfcc
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@ import { Event } from '@theia/core/lib/common/event';
import { FrontendApplicationState } from '@theia/core/lib/common/frontend-application-state';
import { nls } from '@theia/core/lib/common/nls';
import * as React from '@theia/core/shared/react';
import { BoardList } from '../../common/protocol/board-list';
import {
Board,
BoardIdentifier,
BoardsConfig,
BoardWithPackage,
DetectedPort,
findMatchingPortIndex,
Port,
PortIdentifier,
} from '../../common/protocol/boards-service';
import { NotificationCenter } from '../notification-center';

namespace BoardsConfigComponent {
export interface Props {
readonly boardList: BoardList;
/**
* This is not the real config, it's only living in the dialog. Users can change it without update and can cancel any modifications.
*/
readonly boardsConfig: BoardsConfig;
readonly notificationCenter: NotificationCenter;
readonly onFocusNodeSet: (element: HTMLElement | undefined) => void;
readonly onFilteredTextDidChangeEvent: Event<string>;
Expand All @@ -25,6 +30,9 @@ namespace BoardsConfigComponent {
readonly searchBoards: (query?: {
query?: string;
}) => Promise<BoardWithPackage[]>;
readonly ports: (
predicate?: (port: DetectedPort) => boolean
) => readonly DetectedPort[];
}

export interface State {
Expand Down Expand Up @@ -194,15 +202,15 @@ export class BoardsConfigComponent extends React.Component<
}

private renderBoards(): React.ReactNode {
const { boardList } = this.props;
const { boardsConfig } = this.props;
const { searchResults, query } = this.state;
// Board names are not unique per core https://github.com/arduino/arduino-pro-ide/issues/262#issuecomment-661019560
// It is tricky when the core is not yet installed, no FQBNs are available.
const distinctBoards = new Map<string, Board.Detailed>();
const toKey = ({ name, packageName, fqbn }: Board.Detailed) =>
!!fqbn ? `${name}-${packageName}-${fqbn}` : `${name}-${packageName}`;
for (const board of Board.decorateBoards(
boardList.boardsConfig.selectedBoard,
boardsConfig.selectedBoard,
searchResults
)) {
const key = toKey(board);
Expand Down Expand Up @@ -255,9 +263,12 @@ export class BoardsConfigComponent extends React.Component<
}

private renderPorts(): React.ReactNode {
const { boardList } = this.props;
const predicate = this.state.showAllPorts ? undefined : Port.isVisiblePort;
const detectedPorts = boardList.ports(predicate);
const detectedPorts = this.props.ports(predicate);
const matchingIndex = findMatchingPortIndex(
this.props.boardsConfig.selectedPort,
detectedPorts
);
return !detectedPorts.length ? (
<div className="no-result">
{nls.localize('arduino/board/noPortsDiscovered', 'No ports discovered')}
Expand All @@ -269,7 +280,7 @@ export class BoardsConfigComponent extends React.Component<
key={`${Port.keyOf(detectedPort.port)}`}
item={detectedPort.port}
label={Port.toString(detectedPort.port)}
selected={index === detectedPorts.matchingIndex}
selected={index === matchingIndex}
onClick={this.selectPort}
/>
))}
Expand Down
16 changes: 14 additions & 2 deletions arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
BoardIdentifier,
BoardsConfig,
BoardWithPackage,
DetectedPort,
emptyBoardsConfig,
PortIdentifier,
} from '../../common/protocol/boards-service';
Expand Down Expand Up @@ -43,9 +44,11 @@ export class BoardsConfigDialog extends ReactDialog<BoardsConfig> {
private readonly onFilterTextDidChangeEmitter: Emitter<string>;
private readonly onBoardSelected = (board: BoardIdentifier): void => {
this._boardsConfig.selectedBoard = board;
this.update();
};
private readonly onPortSelected = (port: PortIdentifier): void => {
this._boardsConfig.selectedPort = port;
this.update();
};
private readonly setFocusNode = (element: HTMLElement | undefined): void => {
this.focusNode = element;
Expand All @@ -55,6 +58,11 @@ export class BoardsConfigDialog extends ReactDialog<BoardsConfig> {
}): Promise<BoardWithPackage[]> => {
return this.boardsServiceProvider.searchBoards(options);
};
private readonly ports = (
predicate?: (port: DetectedPort) => boolean
): readonly DetectedPort[] => {
return this.boardsServiceProvider.boardList.ports(predicate);
};
private _boardsConfig: BoardsConfig;
private focusNode: HTMLElement | undefined;

Expand All @@ -75,7 +83,10 @@ export class BoardsConfigDialog extends ReactDialog<BoardsConfig> {

@postConstruct()
protected init(): void {
this.boardsServiceProvider.onBoardListDidChange(() => this.update()); // Do not add to `toDispose`!
this.boardsServiceProvider.onBoardListDidChange(() => {
this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig);
this.update();
}); // Do not add to `toDispose`!
this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig);
}

Expand Down Expand Up @@ -118,7 +129,7 @@ export class BoardsConfigDialog extends ReactDialog<BoardsConfig> {
<div id="select-board-dialog" className="p-Widget ps">
<div className="selectBoardContainer">
<BoardsConfigComponent
boardList={this.boardsServiceProvider.boardList}
boardsConfig={this._boardsConfig}
onBoardSelected={this.onBoardSelected}
onPortSelected={this.onPortSelected}
notificationCenter={this.notificationCenter}
Expand All @@ -128,6 +139,7 @@ export class BoardsConfigDialog extends ReactDialog<BoardsConfig> {
}
onAppStateDidChange={this.notificationCenter.onAppStateDidChange}
searchBoards={this.searchBoards}
ports={this.ports}
/>
</div>
</div>
Expand Down
12 changes: 5 additions & 7 deletions arduino-ide-extension/src/common/protocol/board-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DetectedPort,
DetectedPorts,
emptyBoardsConfig,
findMatchingPortIndex,
isBoardIdentifier,
isDefinedBoardsConfig,
Port,
Expand Down Expand Up @@ -227,13 +228,10 @@ export function createBoardList(
}
}
const ports = _allPorts.filter(predicate);
let matchingIndex = -1;
if (boardsConfig.selectedPort) {
const selectedPortKey = Port.keyOf(boardsConfig.selectedPort);
matchingIndex = ports.findIndex(
(detectedPort) => Port.keyOf(detectedPort.port) === selectedPortKey
);
}
const matchingIndex = findMatchingPortIndex(
boardsConfig.selectedPort,
ports
);
return Object.assign(ports, { matchingIndex });
};

Expand Down
19 changes: 17 additions & 2 deletions arduino-ide-extension/src/common/protocol/boards-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ export interface DetectedPort {
readonly port: Port;
readonly boards: Pick<Board, 'name' | 'fqbn'>[];
}

export function findMatchingPortIndex(
toFind: PortIdentifier | undefined,
ports: readonly DetectedPort[] | readonly Port[]
): number {
if (!toFind) {
return -1;
}
const toFindPortKey = Port.keyOf(toFind);
return ports.findIndex((port) => Port.keyOf(port) === toFindPortKey);
}

/**
* The closest representation what the Arduino CLI detects with the `board list --watch` gRPC equivalent.
* The keys are unique identifiers generated from the port object (via `Port#keyOf`).
Expand Down Expand Up @@ -185,8 +197,11 @@ export namespace Port {
/**
* Key is the combination of address and protocol formatted like `'arduino+${protocol}://${address}'` used to uniquely identify a port.
*/
export function keyOf({ protocol, address }: PortIdentifier): string {
return `arduino+${protocol}://${address}`;
export function keyOf(port: PortIdentifier | Port | DetectedPort): string {
if (isPortIdentifier(port)) {
return `arduino+${port.protocol}://${port.address}`;
}
return keyOf(port.port);
}

export function toString({ addressLabel, protocolLabel }: Port): string {
Expand Down

0 comments on commit a92bfcc

Please sign in to comment.