mirror of
https://github.com/Microsoft/vscode
synced 2024-10-04 02:14:06 +00:00
move auto-attach into new built-in extension; fixes #53586
This commit is contained in:
parent
076a754a1c
commit
bf7ac9201e
9
.vscode/launch.json
vendored
9
.vscode/launch.json
vendored
|
@ -236,6 +236,15 @@
|
|||
"VSCODE_DEV": "1",
|
||||
"VSCODE_CLI": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Launch Built-in Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}/extensions/debug-auto-launch"
|
||||
]
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[
|
||||
{
|
||||
"name": "ms-vscode.node-debug",
|
||||
"version": "1.26.1",
|
||||
"version": "1.26.2",
|
||||
"repo": "https://github.com/Microsoft/vscode-node-debug"
|
||||
},
|
||||
{
|
||||
|
|
2
extensions/debug-auto-launch/.vscodeignore
Normal file
2
extensions/debug-auto-launch/.vscodeignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
src/**
|
||||
tsconfig.json
|
54
extensions/debug-auto-launch/package.json
Normal file
54
extensions/debug-auto-launch/package.json
Normal file
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "debug-auto-launch",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"version": "1.0.0",
|
||||
"publisher": "vscode",
|
||||
"engines": {
|
||||
"vscode": "^1.5.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/extension",
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:debug-auto-launch",
|
||||
"watch": "gulp watch-extension:debug-auto-launch"
|
||||
},
|
||||
"contributes": {
|
||||
"configuration": {
|
||||
"title": "Node debug",
|
||||
"properties": {
|
||||
"debug.node.autoAttach": {
|
||||
"scope": "window",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"on",
|
||||
"off"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"%debug.node.autoAttach.disabled.description%",
|
||||
"%debug.node.autoAttach.on.description%",
|
||||
"%debug.node.autoAttach.off.description%"
|
||||
],
|
||||
"description": "%debug.node.autoAttach.description%",
|
||||
"default": "disabled"
|
||||
}
|
||||
}
|
||||
},
|
||||
"commands": [
|
||||
{
|
||||
"command": "extension.node-debug.toggleAutoAttach",
|
||||
"title": "%toggle.auto.attach%",
|
||||
"category": "Debug"
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "8.0.33"
|
||||
}
|
||||
}
|
11
extensions/debug-auto-launch/package.nls.json
Normal file
11
extensions/debug-auto-launch/package.nls.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"displayName": "Node Debug Auto-attach",
|
||||
"description": "Helper for auto-attach feature when node-debug extensions are not active.",
|
||||
|
||||
"debug.node.autoAttach.description": "Automatically attach node debugger when node.js was launched in debug mode from integrated terminal.",
|
||||
"debug.node.autoAttach.disabled.description": "Auto attach is disabled and not shown in status bar.",
|
||||
"debug.node.autoAttach.on.description": "Auto attach is active.",
|
||||
"debug.node.autoAttach.off.description": "Auto attach is inactive.",
|
||||
|
||||
"toggle.auto.attach": "Toggle Auto Attach"
|
||||
}
|
24
extensions/debug-auto-launch/src/autoAttach.ts
Normal file
24
extensions/debug-auto-launch/src/autoAttach.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { basename } from 'path';
|
||||
import { pollProcesses, attachToProcess } from './nodeProcessTree';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export function startAutoAttach(rootPid: number): vscode.Disposable {
|
||||
|
||||
return pollProcesses(rootPid, true, (pid, cmdPath, args) => {
|
||||
const cmdName = basename(cmdPath, '.exe');
|
||||
if (cmdName === 'node') {
|
||||
const name = localize('process.with.pid.label', "Process {0}", pid);
|
||||
attachToProcess(undefined, name, pid, args);
|
||||
}
|
||||
});
|
||||
}
|
132
extensions/debug-auto-launch/src/extension.ts
Normal file
132
extensions/debug-auto-launch/src/extension.ts
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { basename } from 'path';
|
||||
import { pollProcesses, attachToProcess } from './nodeProcessTree';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const ON_TEXT = localize('status.text.auto.attach.on', "Auto Attach: On");
|
||||
const OFF_TEXT = localize('status.text.auto.attach.off', "Auto Attach: Off");
|
||||
|
||||
const TOGGLE_COMMAND = 'extension.node-debug.toggleAutoAttach';
|
||||
|
||||
let currentState: string;
|
||||
let autoAttacher: vscode.Disposable | undefined;
|
||||
let statusItem: vscode.StatusBarItem | undefined = undefined;
|
||||
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
|
||||
context.subscriptions.push(vscode.commands.registerCommand(TOGGLE_COMMAND, toggleAutoAttach));
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('debug.node.autoAttach')) {
|
||||
updateAutoAttachInStatus(context);
|
||||
}
|
||||
}));
|
||||
|
||||
updateAutoAttachInStatus(context);
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
}
|
||||
|
||||
|
||||
function toggleAutoAttach(context: vscode.ExtensionContext) {
|
||||
|
||||
const conf = vscode.workspace.getConfiguration('debug.node');
|
||||
|
||||
let value = conf.get('autoAttach');
|
||||
if (value === 'on') {
|
||||
value = 'off';
|
||||
} else {
|
||||
value = 'on';
|
||||
}
|
||||
|
||||
const info = conf.inspect('autoAttach');
|
||||
let target: vscode.ConfigurationTarget = vscode.ConfigurationTarget.Global;
|
||||
if (info) {
|
||||
if (info.workspaceFolderValue) {
|
||||
target = vscode.ConfigurationTarget.WorkspaceFolder;
|
||||
} else if (info.workspaceValue) {
|
||||
target = vscode.ConfigurationTarget.Workspace;
|
||||
} else if (info.globalValue) {
|
||||
target = vscode.ConfigurationTarget.Global;
|
||||
} else if (info.defaultValue) {
|
||||
// setting not yet used: store setting in workspace
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
target = vscode.ConfigurationTarget.Workspace;
|
||||
}
|
||||
}
|
||||
}
|
||||
conf.update('autoAttach', value, target);
|
||||
|
||||
updateAutoAttachInStatus(context);
|
||||
}
|
||||
|
||||
function updateAutoAttachInStatus(context: vscode.ExtensionContext) {
|
||||
|
||||
const newState = <string>vscode.workspace.getConfiguration('debug.node').get('autoAttach');
|
||||
|
||||
if (newState !== currentState) {
|
||||
|
||||
currentState = newState;
|
||||
|
||||
if (newState === 'disabled') {
|
||||
|
||||
// turn everything off
|
||||
if (statusItem) {
|
||||
statusItem.hide();
|
||||
statusItem.text = OFF_TEXT;
|
||||
}
|
||||
if (autoAttacher) {
|
||||
autoAttacher.dispose();
|
||||
autoAttacher = undefined;
|
||||
}
|
||||
|
||||
} else { // 'on' or 'off'
|
||||
|
||||
// make sure status bar item exists and is visible
|
||||
if (!statusItem) {
|
||||
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||
statusItem.command = TOGGLE_COMMAND;
|
||||
statusItem.text = OFF_TEXT;
|
||||
statusItem.tooltip = localize('status.tooltip.auto.attach', "Automatically attach to node.js processes in debug mode");
|
||||
statusItem.show();
|
||||
context.subscriptions.push(statusItem);
|
||||
} else {
|
||||
statusItem.show();
|
||||
}
|
||||
|
||||
if (newState === 'off') {
|
||||
statusItem.text = OFF_TEXT;
|
||||
if (autoAttacher) {
|
||||
autoAttacher.dispose();
|
||||
autoAttacher = undefined;
|
||||
}
|
||||
} else if (newState === 'on') {
|
||||
statusItem.text = ON_TEXT;
|
||||
const vscode_pid = process.env['VSCODE_PID'];
|
||||
const rootPid = vscode_pid ? parseInt(vscode_pid) : 0;
|
||||
autoAttacher = startAutoAttach(rootPid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startAutoAttach(rootPid: number): vscode.Disposable {
|
||||
|
||||
return pollProcesses(rootPid, true, (pid, cmdPath, args) => {
|
||||
const cmdName = basename(cmdPath, '.exe');
|
||||
if (cmdName === 'node') {
|
||||
const name = localize('process.with.pid.label', "Process {0}", pid);
|
||||
attachToProcess(undefined, name, pid, args);
|
||||
}
|
||||
});
|
||||
}
|
139
extensions/debug-auto-launch/src/nodeProcessTree.ts
Normal file
139
extensions/debug-auto-launch/src/nodeProcessTree.ts
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { getProcessTree, ProcessTreeNode } from './processTree';
|
||||
import { analyseArguments } from './protocolDetection';
|
||||
|
||||
const pids = new Set<number>();
|
||||
|
||||
const POLL_INTERVAL = 1000;
|
||||
|
||||
/**
|
||||
* Poll for all subprocesses of given root process.
|
||||
*/
|
||||
export function pollProcesses(rootPid: number, inTerminal: boolean, cb: (pid: number, cmd: string, args: string) => void): vscode.Disposable {
|
||||
|
||||
let stopped = false;
|
||||
|
||||
function poll() {
|
||||
//const start = Date.now();
|
||||
findChildProcesses(rootPid, inTerminal, cb).then(_ => {
|
||||
//console.log(`duration: ${Date.now() - start}`);
|
||||
setTimeout(_ => {
|
||||
if (!stopped) {
|
||||
poll();
|
||||
}
|
||||
}, POLL_INTERVAL);
|
||||
});
|
||||
}
|
||||
|
||||
poll();
|
||||
|
||||
return new vscode.Disposable(() => stopped = true);
|
||||
}
|
||||
|
||||
export function attachToProcess(folder: vscode.WorkspaceFolder | undefined, name: string, pid: number, args: string, baseConfig?: vscode.DebugConfiguration) {
|
||||
|
||||
if (pids.has(pid)) {
|
||||
return;
|
||||
}
|
||||
pids.add(pid);
|
||||
|
||||
const config: vscode.DebugConfiguration = {
|
||||
type: 'node',
|
||||
request: 'attach',
|
||||
name: name,
|
||||
stopOnEntry: false
|
||||
};
|
||||
|
||||
if (baseConfig) {
|
||||
// selectively copy attributes
|
||||
if (baseConfig.timeout) {
|
||||
config.timeout = baseConfig.timeout;
|
||||
}
|
||||
if (baseConfig.sourceMaps) {
|
||||
config.sourceMaps = baseConfig.sourceMaps;
|
||||
}
|
||||
if (baseConfig.outFiles) {
|
||||
config.outFiles = baseConfig.outFiles;
|
||||
}
|
||||
if (baseConfig.sourceMapPathOverrides) {
|
||||
config.sourceMapPathOverrides = baseConfig.sourceMapPathOverrides;
|
||||
}
|
||||
if (baseConfig.smartStep) {
|
||||
config.smartStep = baseConfig.smartStep;
|
||||
}
|
||||
if (baseConfig.skipFiles) {
|
||||
config.skipFiles = baseConfig.skipFiles;
|
||||
}
|
||||
if (baseConfig.showAsyncStacks) {
|
||||
config.sourceMaps = baseConfig.showAsyncStacks;
|
||||
}
|
||||
if (baseConfig.trace) {
|
||||
config.trace = baseConfig.trace;
|
||||
}
|
||||
}
|
||||
|
||||
let { usePort, protocol, port } = analyseArguments(args);
|
||||
if (usePort) {
|
||||
config.processId = `${protocol}${port}`;
|
||||
} else {
|
||||
if (protocol && port > 0) {
|
||||
config.processId = `${pid}${protocol}${port}`;
|
||||
} else {
|
||||
config.processId = pid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
vscode.debug.startDebugging(folder, config);
|
||||
}
|
||||
|
||||
function findChildProcesses(rootPid: number, inTerminal: boolean, cb: (pid: number, cmd: string, args: string) => void): Promise<void> {
|
||||
|
||||
function walker(node: ProcessTreeNode, terminal: boolean, renderer: number) {
|
||||
|
||||
if (node.args.indexOf('--type=terminal') >= 0 && (renderer === 0 || node.ppid === renderer)) {
|
||||
terminal = true;
|
||||
}
|
||||
|
||||
let { protocol } = analyseArguments(node.args);
|
||||
if (terminal && protocol) {
|
||||
cb(node.pid, node.command, node.args);
|
||||
}
|
||||
|
||||
for (const child of node.children || []) {
|
||||
walker(child, terminal, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
function finder(node: ProcessTreeNode, pid: number): ProcessTreeNode | undefined {
|
||||
if (node.pid === pid) {
|
||||
return node;
|
||||
}
|
||||
for (const child of node.children || []) {
|
||||
const p = finder(child, pid);
|
||||
if (p) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getProcessTree(rootPid).then(tree => {
|
||||
if (tree) {
|
||||
|
||||
// find the pid of the renderer process
|
||||
const extensionHost = finder(tree, process.pid);
|
||||
let rendererPid = extensionHost ? extensionHost.ppid : 0;
|
||||
|
||||
for (const child of tree.children || []) {
|
||||
walker(child, !inTerminal, rendererPid);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
186
extensions/debug-auto-launch/src/processTree.ts
Normal file
186
extensions/debug-auto-launch/src/processTree.ts
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
export class ProcessTreeNode {
|
||||
children?: ProcessTreeNode[];
|
||||
|
||||
constructor(public pid: number, public ppid: number, public command: string, public args: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getProcessTree(rootPid: number): Promise<ProcessTreeNode | undefined> {
|
||||
|
||||
const map = new Map<number, ProcessTreeNode>();
|
||||
|
||||
map.set(0, new ProcessTreeNode(0, 0, '???', ''));
|
||||
|
||||
try {
|
||||
await getProcesses((pid: number, ppid: number, command: string, args: string) => {
|
||||
if (pid !== ppid) {
|
||||
map.set(pid, new ProcessTreeNode(pid, ppid, command, args));
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const values = map.values();
|
||||
for (const p of values) {
|
||||
const parent = map.get(p.ppid);
|
||||
if (parent && parent !== p) {
|
||||
if (!parent.children) {
|
||||
parent.children = [];
|
||||
}
|
||||
parent.children.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNaN(rootPid) && rootPid > 0) {
|
||||
return map.get(rootPid);
|
||||
}
|
||||
return map.get(0);
|
||||
}
|
||||
|
||||
export function getProcesses(one: (pid: number, ppid: number, command: string, args: string, date?: number) => void): Promise<void> {
|
||||
|
||||
// returns a function that aggregates chunks of data until one or more complete lines are received and passes them to a callback.
|
||||
function lines(callback: (a: string) => void) {
|
||||
let unfinished = ''; // unfinished last line of chunk
|
||||
return (data: string | Buffer) => {
|
||||
const lines = data.toString().split(/\r?\n/);
|
||||
const finishedLines = lines.slice(0, lines.length - 1);
|
||||
finishedLines[0] = unfinished + finishedLines[0]; // complete previous unfinished line
|
||||
unfinished = lines[lines.length - 1]; // remember unfinished last line of this chunk for next round
|
||||
for (const s of finishedLines) {
|
||||
callback(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let proc: ChildProcess;
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
|
||||
// attributes columns are in alphabetic order!
|
||||
const CMD_PAT = /^(.*)\s+([0-9]+)\.[0-9]+[+-][0-9]+\s+([0-9]+)\s+([0-9]+)$/;
|
||||
|
||||
const wmic = join(process.env['WINDIR'] || 'C:\\Windows', 'System32', 'wbem', 'WMIC.exe');
|
||||
proc = spawn(wmic, ['process', 'get', 'CommandLine,CreationDate,ParentProcessId,ProcessId']);
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stdout.on('data', lines(line => {
|
||||
let matches = CMD_PAT.exec(line.trim());
|
||||
if (matches && matches.length === 5) {
|
||||
const pid = Number(matches[4]);
|
||||
const ppid = Number(matches[3]);
|
||||
const date = Number(matches[2]);
|
||||
let args = matches[1].trim();
|
||||
if (!isNaN(pid) && !isNaN(ppid) && args) {
|
||||
let command = args;
|
||||
if (args[0] === '"') {
|
||||
const end = args.indexOf('"', 1);
|
||||
if (end > 0) {
|
||||
command = args.substr(1, end - 1);
|
||||
args = args.substr(end + 2);
|
||||
}
|
||||
} else {
|
||||
const end = args.indexOf(' ');
|
||||
if (end > 0) {
|
||||
command = args.substr(0, end);
|
||||
args = args.substr(end + 1);
|
||||
} else {
|
||||
args = '';
|
||||
}
|
||||
}
|
||||
one(pid, ppid, command, args, date);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
} else if (process.platform === 'darwin') { // OS X
|
||||
|
||||
proc = spawn('/bin/ps', ['-x', '-o', `pid,ppid,comm=${'a'.repeat(256)},command`]);
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stdout.on('data', lines(line => {
|
||||
|
||||
const pid = Number(line.substr(0, 5));
|
||||
const ppid = Number(line.substr(6, 5));
|
||||
const command = line.substr(12, 256).trim();
|
||||
const args = line.substr(269 + command.length);
|
||||
|
||||
if (!isNaN(pid) && !isNaN(ppid)) {
|
||||
one(pid, ppid, command, args);
|
||||
}
|
||||
}));
|
||||
|
||||
} else { // linux
|
||||
|
||||
proc = spawn('/bin/ps', ['-ax', '-o', 'pid,ppid,comm:20,command']);
|
||||
proc.stdout.setEncoding('utf8');
|
||||
proc.stdout.on('data', lines(line => {
|
||||
|
||||
const pid = Number(line.substr(0, 5));
|
||||
const ppid = Number(line.substr(6, 5));
|
||||
let command = line.substr(12, 20).trim();
|
||||
let args = line.substr(33);
|
||||
|
||||
let pos = args.indexOf(command);
|
||||
if (pos >= 0) {
|
||||
pos = pos + command.length;
|
||||
while (pos < args.length) {
|
||||
if (args[pos] === ' ') {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
command = args.substr(0, pos);
|
||||
args = args.substr(pos + 1);
|
||||
}
|
||||
|
||||
if (!isNaN(pid) && !isNaN(ppid)) {
|
||||
one(pid, ppid, command, args);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
proc.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
proc.stderr.setEncoding('utf8');
|
||||
proc.stderr.on('data', data => {
|
||||
reject(new Error(data.toString()));
|
||||
});
|
||||
|
||||
proc.on('close', (code, signal) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else if (code > 0) {
|
||||
reject(new Error(`process terminated with exit code: ${code}`));
|
||||
}
|
||||
if (signal) {
|
||||
reject(new Error(`process terminated with signal: ${signal}`));
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
//resolve();
|
||||
} else if (code > 0) {
|
||||
reject(new Error(`process terminated with exit code: ${code}`));
|
||||
}
|
||||
if (signal) {
|
||||
reject(new Error(`process terminated with signal: ${signal}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
58
extensions/debug-auto-launch/src/protocolDetection.ts
Normal file
58
extensions/debug-auto-launch/src/protocolDetection.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
export const INSPECTOR_PORT_DEFAULT = 9229;
|
||||
export const LEGACY_PORT_DEFAULT = 5858;
|
||||
|
||||
export interface DebugArguments {
|
||||
usePort: boolean; // if true debug by using the debug port
|
||||
protocol?: 'legacy' | 'inspector';
|
||||
address?: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
/*
|
||||
* analyse the given command line arguments and extract debug port and protocol from it.
|
||||
*/
|
||||
export function analyseArguments(args: string): DebugArguments {
|
||||
|
||||
const DEBUG_FLAGS_PATTERN = /--(inspect|debug)(-brk)?(=((\[[0-9a-fA-F:]*\]|[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|[a-zA-Z0-9\.]*):)?(\d+))?/;
|
||||
const DEBUG_PORT_PATTERN = /--(inspect|debug)-port=(\d+)/;
|
||||
|
||||
const result: DebugArguments = {
|
||||
usePort: false,
|
||||
port: -1
|
||||
};
|
||||
|
||||
// match --debug, --debug=1234, --debug-brk, debug-brk=1234, --inspect, --inspect=1234, --inspect-brk, --inspect-brk=1234
|
||||
let matches = DEBUG_FLAGS_PATTERN.exec(args);
|
||||
if (matches && matches.length >= 2) {
|
||||
// attach via port
|
||||
result.usePort = true;
|
||||
if (matches.length >= 6 && matches[5]) {
|
||||
result.address = matches[5];
|
||||
}
|
||||
if (matches.length >= 7 && matches[6]) {
|
||||
result.port = parseInt(matches[6]);
|
||||
}
|
||||
result.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
|
||||
}
|
||||
|
||||
// a debug-port=1234 or --inspect-port=1234 overrides the port
|
||||
matches = DEBUG_PORT_PATTERN.exec(args);
|
||||
if (matches && matches.length === 3) {
|
||||
// override port
|
||||
result.port = parseInt(matches[2]);
|
||||
result.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
|
||||
}
|
||||
|
||||
if (result.port < 0) {
|
||||
result.port = result.protocol === 'inspector' ? INSPECTOR_PORT_DEFAULT : LEGACY_PORT_DEFAULT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
7
extensions/debug-auto-launch/src/typings/ref.d.ts
vendored
Normal file
7
extensions/debug-auto-launch/src/typings/ref.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
16
extensions/debug-auto-launch/tsconfig.json
Normal file
16
extensions/debug-auto-launch/tsconfig.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"outDir": "./out",
|
||||
"lib": [
|
||||
"es2015"
|
||||
],
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"downlevelIteration": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
11
extensions/debug-auto-launch/yarn.lock
Normal file
11
extensions/debug-auto-launch/yarn.lock
Normal file
|
@ -0,0 +1,11 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@8.0.33":
|
||||
version "8.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd"
|
||||
|
||||
vscode-nls@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.4.tgz#2166b4183c8aea884d20727f5449e62be69fd398"
|
Loading…
Reference in a new issue