/*--------------------------------------------------------- * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ import * as vscode from 'vscode'; import * as Core from 'vscode-chrome-debug-core'; import * as nls from 'vscode-nls'; import { defaultTargetFilter, getTargetFilter } from './utils'; const localize = nls.loadMessageBundle(); export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('extension.chrome-debug.toggleSkippingFile', toggleSkippingFile)); context.subscriptions.push(vscode.commands.registerCommand('extension.chrome-debug.toggleSmartStep', toggleSmartStep)); context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('chrome', new ChromeConfigurationProvider())); } export function deactivate() { } const DEFAULT_CONFIG = { type: 'chrome', request: 'launch', name: localize('chrome.launch.name', 'Launch Chrome against localhost'), url: 'http://localhost:8080', webRoot: '${workspaceFolder}' }; export class ChromeConfigurationProvider implements vscode.DebugConfigurationProvider { provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult { return Promise.resolve([DEFAULT_CONFIG]); } /** * Try to add all missing attributes to the debug configuration being launched. */ async resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): Promise { // if launch.json is missing or empty if (!config.type && !config.request && !config.name) { // Return null so it will create a launch.json and fall back on provideDebugConfigurations - better to point the user towards the config // than try to work automagically. return null; } if (config.request === 'attach') { const discovery = new Core.chromeTargetDiscoveryStrategy.ChromeTargetDiscovery( new Core.NullLogger(), new Core.telemetry.NullTelemetryReporter()); let targets; try { targets = await discovery.getAllTargets(config.address || '127.0.0.1', config.port, config.targetTypes === undefined ? defaultTargetFilter : getTargetFilter(config.targetTypes), config.url || config.urlFilter); } catch (e) { // Target not running? } if (targets && targets.length > 1) { const selectedTarget = await pickTarget(targets); if (!selectedTarget) { // Quickpick canceled, bail return null; } config.websocketUrl = selectedTarget.websocketDebuggerUrl; } } return config; } } function toggleSkippingFile(path: string): void { if (!path) { const activeEditor = vscode.window.activeTextEditor; path = activeEditor && activeEditor.document.fileName; } if (path && vscode.debug.activeDebugSession) { const args: Core.IToggleSkipFileStatusArgs = typeof path === 'string' ? { path } : { sourceReference: path }; vscode.debug.activeDebugSession.customRequest('toggleSkipFileStatus', args); } } function toggleSmartStep(): void { if (vscode.debug.activeDebugSession) { vscode.debug.activeDebugSession.customRequest('toggleSmartStep'); } } interface ITargetQuickPickItem extends vscode.QuickPickItem { websocketDebuggerUrl: string; } async function pickTarget(targets: Core.chromeConnection.ITarget[]): Promise { const items = targets.map(target => ({ label: unescapeTargetTitle(target.title), detail: target.url, websocketDebuggerUrl: target.webSocketDebuggerUrl })); const placeHolder = localize('chrome.targets.placeholder', 'Select a tab'); const selected = await vscode.window.showQuickPick(items, { placeHolder, matchOnDescription: true, matchOnDetail: true }); return selected; } function unescapeTargetTitle(title: string): string { return title .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/'/g, `'`) .replace(/"/g, '"'); }