blob: 79cc32c875eea5e7c9a0a3dfd4a0342208dcbefe [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as vscode from 'vscode';
import { Ffx, FfxEventType, FuchsiaDevice } from './ffx';
import * as logger from './logger';
import { COMMAND_TARGET_SELECT_ID } from './common-config';
const STATUS_BAR_PRIORITY = 0;
// Exported so it is accessible in the test module.
export const STATUS_PREFIX_EMPTY = '$(circle-slash)';
export const STATUS_PREFIX_NOT_CONNECTED = '$(vm-outline)';
export const STATUS_PREFIX_CONNECTED = '$(vm)';
/**
* Class that holds quick pick item data for the function showQuickPick(). Each instance is
* presented as a row in a menu created when clicking on the target status bar widget.
*/
export class TargetPickAction implements vscode.QuickPickItem {
label: string;
picked?: boolean | undefined;
device: FuchsiaDevice;
command: string;
constructor(label: string, device: FuchsiaDevice, command: string) {
this.label = label;
this.device = device;
this.command = command;
}
}
/**
* Status bar widget to query and send commands to the target (fuchsia device).
*/
export class TargetStatusBarItem {
private ffxTools: Ffx;
private fuchsiaStatusBarItem: vscode.StatusBarItem;
private setBarItemText(targetName: string | undefined, connected: boolean) {
let displayName: string;
let icon: string;
let backgroundColor: vscode.ThemeColor | undefined;
if (targetName === undefined) {
icon = STATUS_PREFIX_EMPTY;
displayName = 'Not connected';
backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
} else if (!connected) {
icon = STATUS_PREFIX_NOT_CONNECTED;
displayName = `${targetName} (not connected)`;
backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
} else {
icon = STATUS_PREFIX_CONNECTED;
displayName = targetName;
backgroundColor = undefined;
}
this.fuchsiaStatusBarItem.text = `${icon} ${displayName}`;
this.fuchsiaStatusBarItem.tooltip = `Fuchsia target device: ${displayName}`;
this.fuchsiaStatusBarItem.backgroundColor = backgroundColor;
}
// Build the list of QuickPickItems for targets.
// The first item in the list is the default target, followed by the actions
// that can be performed on that target.
// Items to set the other targets as the default follow.
private buildTargetQuickPickItems(targetList: { [key: string]: FuchsiaDevice }):
TargetPickAction[] {
let items: TargetPickAction[] = [];
for (let key in targetList) {
let device = targetList[key];
// Ignore devices that are not connected.
if (!device.connected) { continue; }
if (device.isDefault) {
// Add items to front of list.
let deviceItem = new TargetPickAction(`Default target: ${key}`, device,
'fuchsia.internal.target.setDefault');
deviceItem.picked = true;
let rebootItem = new TargetPickAction(`Reboot ${key}`, device,
'fuchsia.target.reboot');
let poweroffItem = new TargetPickAction(`Power off ${key}`, device,
'fuchsia.target.powerOff');
let logItem = new TargetPickAction(`Show log for ${key}`, device,
'fuchsia.viewLogs');
items = [deviceItem, logItem, rebootItem, poweroffItem, ...items];
} else {
items.push(new TargetPickAction(`Set ${key} as default`, device,
'fuchsia.internal.target.setDefault'));
}
}
return items;
}
constructor(readonly contextSubscriptions: { dispose(): any }[], ffxTools: Ffx) {
this.ffxTools = ffxTools;
// Menu for target actions
contextSubscriptions.push(
vscode.commands.registerCommand(COMMAND_TARGET_SELECT_ID, async () => {
// Try to find the ffx path again if it is not set.
if (this.ffxTools.hasValidFfxPath() === false) {
await this.ffxTools.toolFinder?.updateFfxPath(false);
}
this.ffxTools.getTargetList().then(async targetList => {
let items = this.buildTargetQuickPickItems(targetList);
if (items.length > 0) {
let action = await vscode.window.showQuickPick(items);
if (action === undefined) {
return;
}
await vscode.commands.executeCommand(action.command, action.device);
} else {
let msg = Object.keys(targetList).length > 0 ?
'No available devices found.' : 'No devices found.';
logger.warn(msg);
void vscode.window.showWarningMessage(msg);
}
})
// If there is a problem getting the list, just log it. The quickpick
// will be empty.
.catch(err => {
logger.warn(`Could not build target list: ${err}`);
void vscode.window.showWarningMessage('Failed to retrieve devices.');
});
})
);
// Target status-bar item
this.fuchsiaStatusBarItem = vscode.window
.createStatusBarItem(vscode.StatusBarAlignment.Left, STATUS_BAR_PRIORITY);
this.fuchsiaStatusBarItem.command = COMMAND_TARGET_SELECT_ID;
this.fuchsiaStatusBarItem.tooltip = 'Fuchsia target device.';
contextSubscriptions.push(this.fuchsiaStatusBarItem);
this.setBarItemText(/*targetName*/ undefined, /*Connected*/ false);
this.fuchsiaStatusBarItem.show();
// Clear the default target if there is no ffx found.
this.ffxTools.onDidChangeConfiguration(eventType => {
switch (eventType) {
case FfxEventType.ffxPathReset:
this.setBarItemText(/*targetName*/ undefined, /*Connected*/ false);
break;
}
});
// When the default target is set, update the item text.
this.ffxTools.onSetTarget(target => {
this.setBarItemText(target?.nodeName, target?.connected ?? false);
});
}
}