Skip to content

Commit

Permalink
Support debugging process from the process explorer, closes #63147 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Rachel Macfarlane committed Nov 30, 2018
1 parent 7cd7e37 commit 86052e3
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 26 deletions.
10 changes: 7 additions & 3 deletions src/vs/code/electron-browser/issue/issueReporterMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,15 +378,19 @@ export class IssueReporter extends Disposable {

this.previewButton.onDidClick(() => this.createIssue());

function sendWorkbenchCommand(commandId: string) {
ipcRenderer.send('vscode:workbenchCommand', { id: commandId, from: 'issueReporter' });
}

this.addEventListener('disableExtensions', 'click', () => {
ipcRenderer.send('vscode:workbenchCommand', 'workbench.action.reloadWindowWithExtensionsDisabled');
sendWorkbenchCommand('workbench.action.reloadWindowWithExtensionsDisabled');
});

this.addEventListener('disableExtensions', 'keydown', (e: KeyboardEvent) => {
e.stopPropagation();
if (e.keyCode === 13 || e.keyCode === 32) {
ipcRenderer.send('vscode:workbenchCommand', 'workbench.extensions.action.disableAll');
ipcRenderer.send('vscode:workbenchCommand', 'workbench.action.reloadWindow');
sendWorkbenchCommand('workbench.extensions.action.disableAll');
sendWorkbenchCommand('workbench.action.reloadWindow');
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import { popup } from 'vs/base/parts/contextmenu/electron-browser/contextmenu';
let processList: any[];
let mapPidToWindowTitle = new Map<number, string>();

const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;

function getProcessList(rootProcess: ProcessItem) {
const processes: any[] = [];

Expand Down Expand Up @@ -62,6 +65,40 @@ function getProcessItem(processes: any[], item: ProcessItem, indent: number): vo
}
}

function isDebuggable(cmd: string): boolean {
const matches = DEBUG_FLAGS_PATTERN.exec(cmd);
return (matches && matches.length >= 2) || cmd.indexOf('node ') >= 0 || cmd.indexOf('node.exe') >= 0;
}

function attachTo(item: ProcessItem) {
const config: any = {
type: 'node',
request: 'attach',
name: `process ${item.pid}`
};

let matches = DEBUG_FLAGS_PATTERN.exec(item.cmd);
if (matches && matches.length >= 2) {
// attach via port
if (matches.length === 4 && matches[3]) {
config.port = parseInt(matches[3]);
}
config.protocol = matches[1] === 'debug' ? 'legacy' : 'inspector';
} else {
// no port -> try to attach via pid (send SIGUSR1)
config.processId = String(item.pid);
}

// a debug-port=n or inspect-port=n overrides the port
matches = DEBUG_PORT_PATTERN.exec(item.cmd);
if (matches && matches.length === 3) {
// override port
config.port = parseInt(matches[2]);
}

ipcRenderer.send('vscode:workbenchCommand', { id: 'workbench.action.debug.start', from: 'processExplorer', args: [config] });
}

function getProcessIdWithHighestProperty(processList, propertyName: string) {
let max = 0;
let maxProcessId;
Expand Down Expand Up @@ -190,6 +227,20 @@ function showContextMenu(e) {
}
}
});

const item = processList.filter(process => process.pid === pid)[0];
if (item && isDebuggable(item.cmd)) {
items.push({
type: 'separator'
});

items.push({
label: localize('debug', "Debug"),
click() {
attachTo(item);
}
});
}
} else {
items.push({
label: localize('copyAll', "Copy All"),
Expand Down
50 changes: 34 additions & 16 deletions src/vs/platform/issue/electron-main/issueService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
export class IssueService implements IIssueService {
_serviceBrand: any;
_issueWindow: BrowserWindow | null;
_issueParentWindow: BrowserWindow;
_issueParentWindow: BrowserWindow | null;
_processExplorerWindow: BrowserWindow | null;
_processExplorerParentWindow: BrowserWindow | null;

constructor(
private machineId: string,
Expand All @@ -49,9 +50,23 @@ export class IssueService implements IIssueService {
});
});

ipcMain.on('vscode:workbenchCommand', (event, arg) => {
if (this._issueParentWindow) {
this._issueParentWindow.webContents.send('vscode:runAction', { id: arg, from: 'issueReporter' });
ipcMain.on('vscode:workbenchCommand', (_, commandInfo) => {
const { id, from, args } = commandInfo;

let parentWindow: BrowserWindow | null;
switch (from) {
case 'issueReporter':
parentWindow = this._issueParentWindow;
break;
case 'processExplorer':
parentWindow = this._processExplorerParentWindow;
break;
default:
throw new Error(`Unexpected command source: ${from}`);
}

if (parentWindow) {
parentWindow.webContents.send('vscode:runAction', { id, from, args });
}
});

Expand All @@ -75,10 +90,11 @@ export class IssueService implements IIssueService {

openReporter(data: IssueReporterData): Promise<void> {
return new Promise(_ => {
this._issueParentWindow = BrowserWindow.getFocusedWindow();
if (this._issueParentWindow) {
const position = this.getWindowPosition(this._issueParentWindow, 700, 800);
if (!this._issueWindow) {
if (!this._issueWindow) {
this._issueParentWindow = BrowserWindow.getFocusedWindow();
if (this._issueParentWindow) {
const position = this.getWindowPosition(this._issueParentWindow, 700, 800);

this._issueWindow = new BrowserWindow({
width: position.width,
height: position.height,
Expand Down Expand Up @@ -107,7 +123,9 @@ export class IssueService implements IIssueService {
}
});
}
}

if (this._issueWindow) {
this._issueWindow.focus();
}
});
Expand All @@ -117,9 +135,9 @@ export class IssueService implements IIssueService {
return new Promise(_ => {
// Create as singleton
if (!this._processExplorerWindow) {
const parentWindow = BrowserWindow.getFocusedWindow();
if (parentWindow) {
const position = this.getWindowPosition(parentWindow, 800, 300);
this._processExplorerParentWindow = BrowserWindow.getFocusedWindow();
if (this._processExplorerParentWindow) {
const position = this.getWindowPosition(this._processExplorerParentWindow, 800, 300);
this._processExplorerWindow = new BrowserWindow({
skipTaskbar: true,
resizable: true,
Expand Down Expand Up @@ -156,18 +174,18 @@ export class IssueService implements IIssueService {

this._processExplorerWindow.on('close', () => this._processExplorerWindow = null);

parentWindow.on('close', () => {
this._processExplorerParentWindow.on('close', () => {
if (this._processExplorerWindow) {
this._processExplorerWindow.close();
this._processExplorerWindow = null;
}
});
}
}

// Focus
if (this._processExplorerWindow) {
this._processExplorerWindow.focus();
}
// Focus
if (this._processExplorerWindow) {
this._processExplorerWindow.focus();
}
});
}
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/windows/common/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ export interface IWindowConfiguration extends ParsedArgs {
export interface IRunActionInWindowRequest {
id: string;
from: 'menu' | 'touchbar' | 'mouse';
args?: any[];
}

export class ActiveWindowManager implements IDisposable {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/electron-browser/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class ElectronWindow extends Themable {

// Support runAction event
ipc.on('vscode:runAction', (event: any, request: IRunActionInWindowRequest) => {
const args: any[] = [];
const args: any[] = request.args || [];

// If we run an action from the touchbar, we fill in the currently active resource
// as payload because the touch bar items are context aware depending on the editor
Expand Down
10 changes: 8 additions & 2 deletions src/vs/workbench/parts/debug/browser/debugActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IFileService } from 'vs/platform/files/common/files';
import { IDebugService, State, IDebugSession, IThread, IEnablement, IBreakpoint, IStackFrame, REPL_ID }
import { IDebugService, State, IDebugSession, IThread, IEnablement, IBreakpoint, IStackFrame, REPL_ID, IConfig }
from 'vs/workbench/parts/debug/common/debug';
import { Variable, Expression, Thread, Breakpoint } from 'vs/workbench/parts/debug/common/debugModel';
import { IPartService } from 'vs/workbench/services/part/common/partService';
Expand Down Expand Up @@ -133,7 +133,13 @@ export class StartAction extends AbstractDebugAction {
this.toDispose.push(this.contextService.onDidChangeWorkbenchState(() => this.updateEnablement()));
}

public run(): Thenable<any> {
// Note: When this action is executed from the process explorer, a config is passed. For all
// other cases it is run with no arguments.
public run(config?: IConfig): Thenable<any> {
if (config) {
return this.debugService.startDebugging(undefined, config, this.isNoDebug());
}

const configurationManager = this.debugService.getConfigurationManager();
let launch = configurationManager.selectedConfiguration.launch;
if (!launch || launch.getConfigurationNames().length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { KeybindingWeight, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { KeybindingWeight, IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actions';
import { ShowViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
Expand Down Expand Up @@ -49,11 +49,13 @@ import { DebugViewlet } from 'vs/workbench/parts/debug/browser/debugViewlet';
import { Repl, ClearReplAction } from 'vs/workbench/parts/debug/electron-browser/repl';
import { DebugQuickOpenHandler } from 'vs/workbench/parts/debug/browser/debugQuickOpen';
import { DebugStatus } from 'vs/workbench/parts/debug/browser/debugStatus';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { LoadedScriptsView } from 'vs/workbench/parts/debug/browser/loadedScriptsView';
import { TOGGLE_LOG_POINT_ID, TOGGLE_CONDITIONAL_BREAKPOINT_ID, TOGGLE_BREAKPOINT_ID } from 'vs/workbench/parts/debug/browser/debugEditorActions';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';

class OpenDebugViewletAction extends ShowViewletAction {
public static readonly ID = VIEWLET_ID;
Expand Down Expand Up @@ -129,8 +131,59 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually);

const debugCategory = nls.localize('debugCategory', "Debug");
registry.registerWorkbenchAction(new SyncActionDescriptor(
StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated()), 'Debug: Start Debugging', debugCategory);

const startDebugDescriptor = new SyncActionDescriptor(StartAction, StartAction.ID, StartAction.LABEL, { primary: KeyCode.F5 }, CONTEXT_IN_DEBUG_MODE.toNegated());

function startDebugHandler(accessor, args): Promise<void> {
const notificationService = accessor.get(INotificationService);
const instantiationService = accessor.get(IInstantiationService);
const lifecycleService = accessor.get(ILifecycleService);

return Promise.resolve(lifecycleService.when(LifecyclePhase.Ready).then(() => {
const actionInstance = instantiationService.createInstance(startDebugDescriptor.syncDescriptor);
try {
// don't run the action when not enabled
if (!actionInstance.enabled) {
actionInstance.dispose();

return void 0;
}

const from = args && args.from || 'keybinding';

if (args) {
delete args.from;
}

return Promise.resolve(actionInstance.run(args, { from })).then(() => {
actionInstance.dispose();
}, err => {
actionInstance.dispose();

return Promise.reject(err);
});
} catch (err) {
actionInstance.dispose();

return Promise.reject(err);
}
})).then(null, err => notificationService.error(err));
}

KeybindingsRegistry.registerCommandAndKeybindingRule({
id: StartAction.ID,
weight: KeybindingWeight.WorkbenchContrib,
when: CONTEXT_IN_DEBUG_MODE.toNegated(),
primary: KeyCode.F5,
handler: startDebugHandler
});

MenuRegistry.addCommand({
id: StartAction.ID,
title: StartAction.LABEL,
category: debugCategory
});

registry.registerWorkbenchAction(new SyncActionDescriptor(StepOverAction, StepOverAction.ID, StepOverAction.LABEL, { primary: KeyCode.F10 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Step Over', debugCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(StepIntoAction, StepIntoAction.ID, StepIntoAction.LABEL, { primary: KeyCode.F11 }, CONTEXT_IN_DEBUG_MODE, KeybindingWeight.WorkbenchContrib + 1), 'Debug: Step Into', debugCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(StepOutAction, StepOutAction.ID, StepOutAction.LABEL, { primary: KeyMod.Shift | KeyCode.F11 }, CONTEXT_IN_DEBUG_MODE), 'Debug: Step Out', debugCategory);
Expand Down

0 comments on commit 86052e3

Please sign in to comment.