blob: 3ec7dc1cd5830dffe09d1057335b068c699f7f81 [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.
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { spawn } from 'child_process';
import { disposeAnalytics, initAnalytics, setUpAnalyticsEvents } from './analytics/setup';
import { ComponentExplorerDataProvider } from './components/explorer';
import { LoggingViewProvider } from './logging/view_provider';
import { ToolFinder } from './tool_finder';
import { Ffx } from './ffx';
import { Fx } from './fx';
import * as logger from './logger';
import { TargetStatusBarItem } from './target_status_bar_item';
import { FuchsiaDevice } from './ffx';
import { setUpZxdb } from './zxdb/zxdb';
import { setUpTestController } from './testing/controller';
import * as flags from './feature-flags';
/**
* contains common bits needed by the various setup functions below
*/
export class Setup {
/**
* a handle to interact with ffx
*/
ffx: Ffx;
/**
* a handle to interact with fx
*/
fx: Fx;
constructor(ctx: vscode.ExtensionContext) {
const toolFinder = new ToolFinder();
this.ffx = toolFinder.ffx;
this.fx = toolFinder.fx;
}
}
/**
* called automatically by vscode when activating the plugin
* (see package.json for activation points)
*/
export async function activate(ctx: vscode.ExtensionContext) {
flags.activate(ctx.extension.packageJSON.version);
// Initialize the logging first so it can be used by all other code.
const log = vscode.window.createOutputChannel('Fuchsia SDK');
logger.initLogger(log);
// Init analytics before possible calls to other Fuchsia tools (e.g. ffx),
// such that the extension could display the analytics notices properly.
try {
await initAnalytics(ctx);
} catch (err) {
// if analytics fails to initialize, it's not catastrophic,
// so just continue on after logging
logger.error('Unable to set up analytics, boldly continuing', undefined, err);
};
let setup = new Setup(ctx);
// TODO(fxbug.dev/98651): we're currently doing this every program
// start -- we should find a better activation point
ctx.subscriptions.push(
vscode.commands.registerCommand('fuchsia.sendFeedback', () => {
// The code you place here will be executed every time your command is executed
void /* in bg */ vscode.env.openExternal(vscode.Uri.parse(
'https://bugs.fuchsia.dev/p/fuchsia/issues/entry?template=Fuchsia+Editor+Tooling'));
}),
);
setUpLoggingView(ctx, setup);
setUpEmulatorInteraction(ctx, setup);
setUpTargetInteraction(ctx, setup);
setUpZxdb(ctx, setup);
setUpComponentInteraction(ctx, setup);
setUpTestController(ctx, setup);
// Set up analytics events as the last step, as ffx calls in the activation process should not be
// considered as user initiated actions.
setUpAnalyticsEvents(setup.ffx);
}
/**
* called automatically by vscode when deactivating the plugin
*/
export function deactivate() {
disposeAnalytics();
flags.deactivate();
}
/**
* initialize the logging view & related commands
*/
function setUpLoggingView(ctx: vscode.ExtensionContext, setup: Setup) {
// initialize the view
const loggingProvider = new LoggingViewProvider(ctx.extensionUri, setup.ffx);
ctx.subscriptions.push(
vscode.window.registerWebviewViewProvider(LoggingViewProvider.viewType, loggingProvider));
// set up command-palette commands
ctx.subscriptions.push(
vscode.commands.registerCommand('fuchsia.viewLogs', (device?: FuchsiaDevice) => {
void /* in bg */ loggingProvider.resetAndShowView(device);
})
);
}
/**
* initialize the target interaction commands (reboot, set target, etc)
* and status bar item.
*/
function setUpEmulatorInteraction(ctx: vscode.ExtensionContext, setup: Setup) {
let registerSimpleEmulatorCommand = (commandName: string,
command: () => Promise<string>) => {
ctx.subscriptions.push(
vscode.commands.registerCommand(commandName,
async () => {
try {
let output = await command();
logger.info(output, 'fuchsia');
} catch (err: any) {
void vscode.window.showErrorMessage(err);
}
})
);
};
registerSimpleEmulatorCommand('fuchsia.emu.start',
setup.ffx.startEmulator.bind(setup.ffx));
registerSimpleEmulatorCommand('fuchsia.emu.stop',
setup.ffx.stopEmulator.bind(setup.ffx));
}
/**
* initialize the target interaction commands (reboot, set target, etc)
* and status bar item.
*/
function setUpTargetInteraction(ctx: vscode.ExtensionContext, setup: Setup) {
let registerSimpleTargetCommand = (commandName: string,
command: (device?: FuchsiaDevice) => Promise<string>) => {
ctx.subscriptions.push(
vscode.commands.registerCommand(commandName,
async (device?: FuchsiaDevice) => {
try {
let output = await command(device);
logger.info(output, 'fuchsia');
} catch (err: any) {
void vscode.window.showErrorMessage(err);
}
})
);
};
// set up commands...
registerSimpleTargetCommand('fuchsia.target.reboot',
setup.ffx.rebootTarget.bind(setup.ffx));
registerSimpleTargetCommand('fuchsia.target.show',
setup.ffx.showTarget.bind(setup.ffx));
registerSimpleTargetCommand('fuchsia.target.powerOff',
setup.ffx.poweroffTarget.bind(setup.ffx));
ctx.subscriptions.push(
vscode.commands.registerCommand('fuchsia.target.snapshot',
async (device?: FuchsiaDevice) => {
let path = await setup.ffx.exportSnapshotToCWD(device);
let msg = `snapshot exported to ${path}`;
logger.info(msg, 'fuchsia');
if (await vscode.window.showInformationMessage(msg, 'Open folder')) {
spawn('xdg-open', [path]);
}
})
);
ctx.subscriptions.push(
vscode.commands.registerCommand('fuchsia.internal.target.setDefault',
async (device?: FuchsiaDevice) => {
if (!device) {
void vscode.window.showErrorMessage('A device must be selected to set as the default target.');
return;
}
try {
let output = await setup.ffx.defaultTarget(device);
logger.debug(`Result from setting default target: ${output}`);
} catch (err: any) {
void vscode.window.showErrorMessage(err);
}
})
);
// ...and the status bar item
new TargetStatusBarItem(ctx.subscriptions, setup.ffx);
}
/**
* initialize the component interaction commands (explorer, etc)
*/
function setUpComponentInteraction(ctx: vscode.ExtensionContext, setup: Setup) {
const componentExplorer = new ComponentExplorerDataProvider(setup.ffx);
vscode.window.registerTreeDataProvider('vscode-fuchsia.componentExplorer', componentExplorer);
vscode.commands.registerCommand('fuchsia.refreshComponentExplorer', () =>
componentExplorer.refresh()
);
}