未验证 提交 86052e38 编写于 作者: R Rachel Macfarlane 提交者: GitHub

Support debugging process from the process explorer, closes #63147 (#63953)

上级 7cd7e374
......@@ -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');
}
});
......
......@@ -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[] = [];
......@@ -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;
......@@ -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"),
......
......@@ -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,
......@@ -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 });
}
});
......@@ -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,
......@@ -107,7 +123,9 @@ export class IssueService implements IIssueService {
}
});
}
}
if (this._issueWindow) {
this._issueWindow.focus();
}
});
......@@ -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,
......@@ -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();
}
});
}
......
......@@ -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 {
......
......@@ -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
......
......@@ -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';
......@@ -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) {
......
......@@ -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';
......@@ -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;
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册