mirror of
https://github.com/Microsoft/vscode
synced 2024-06-30 23:04:56 +00:00
splits up process explorer and issue reporter services (#216766)
* split up process explorer and issue reporter services * more cleanup * fix comment * remove comments
This commit is contained in:
parent
ee173b0e65
commit
4bbebd8af9
|
@ -52,8 +52,9 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
|
|||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IIssueMainService } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IProcessMainService } from 'vs/platform/issue/common/issue';
|
||||
import { IssueMainService } from 'vs/platform/issue/electron-main/issueMainService';
|
||||
import { ProcessMainService } from 'vs/platform/issue/electron-main/processMainService';
|
||||
import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService';
|
||||
import { ILaunchMainService, LaunchMainService } from 'vs/platform/launch/electron-main/launchMainService';
|
||||
import { ILifecycleMainService, LifecycleMainPhase, ShutdownReason } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
|
@ -121,7 +122,6 @@ import { Lazy } from 'vs/base/common/lazy';
|
|||
import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows';
|
||||
import { AuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService';
|
||||
import { normalizeNFC } from 'vs/base/common/normalization';
|
||||
|
||||
/**
|
||||
* The main VS Code application. There will only ever be one instance,
|
||||
* even if the user starts many instances (e.g. from the command line).
|
||||
|
@ -1051,6 +1051,9 @@ export class CodeApplication extends Disposable {
|
|||
// Issues
|
||||
services.set(IIssueMainService, new SyncDescriptor(IssueMainService, [this.userEnv]));
|
||||
|
||||
// Process
|
||||
services.set(IProcessMainService, new SyncDescriptor(ProcessMainService, [this.userEnv]));
|
||||
|
||||
// Encryption
|
||||
services.set(IEncryptionMainService, new SyncDescriptor(EncryptionMainService));
|
||||
|
||||
|
@ -1183,6 +1186,10 @@ export class CodeApplication extends Disposable {
|
|||
const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService), disposables);
|
||||
mainProcessElectronServer.registerChannel('issue', issueChannel);
|
||||
|
||||
// Process
|
||||
const processChannel = ProxyChannel.fromService(accessor.get(IProcessMainService), disposables);
|
||||
mainProcessElectronServer.registerChannel('process', processChannel);
|
||||
|
||||
// Encryption
|
||||
const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService), disposables);
|
||||
mainProcessElectronServer.registerChannel('encryption', encryptionChannel);
|
||||
|
|
|
@ -127,18 +127,25 @@ export const IIssueMainService = createDecorator<IIssueMainService>('issueServic
|
|||
|
||||
export interface IIssueMainService {
|
||||
readonly _serviceBrand: undefined;
|
||||
stopTracing(): Promise<void>;
|
||||
openReporter(data: IssueReporterData): Promise<void>;
|
||||
openProcessExplorer(data: ProcessExplorerData): Promise<void>;
|
||||
getSystemStatus(): Promise<string>;
|
||||
|
||||
// Used by the issue reporter
|
||||
|
||||
$getSystemInfo(): Promise<SystemInfo>;
|
||||
$getPerformanceInfo(): Promise<PerformanceInfo>;
|
||||
openReporter(data: IssueReporterData): Promise<void>;
|
||||
$reloadWithExtensionsDisabled(): Promise<void>;
|
||||
$showConfirmCloseDialog(): Promise<void>;
|
||||
$showClipboardDialog(): Promise<boolean>;
|
||||
$sendReporterMenu(extensionId: string, extensionName: string): Promise<IssueReporterData | undefined>;
|
||||
$closeReporter(): Promise<void>;
|
||||
}
|
||||
|
||||
export const IProcessMainService = createDecorator<IProcessMainService>('processService');
|
||||
|
||||
export interface IProcessMainService {
|
||||
readonly _serviceBrand: undefined;
|
||||
getSystemStatus(): Promise<string>;
|
||||
stopTracing(): Promise<void>;
|
||||
openProcessExplorer(data: ProcessExplorerData): Promise<void>;
|
||||
|
||||
// Used by the process explorer
|
||||
$getSystemInfo(): Promise<SystemInfo>;
|
||||
$getPerformanceInfo(): Promise<PerformanceInfo>;
|
||||
}
|
||||
|
|
|
@ -3,35 +3,26 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions, contentTracing, Display, IpcMainEvent, screen } from 'electron';
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions, Display, screen } from 'electron';
|
||||
import { arch, release, type } from 'os';
|
||||
import { raceTimeout } from 'vs/base/common/async';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { randomPath } from 'vs/base/common/extpath';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
|
||||
import { listProcesses } from 'vs/base/node/ps';
|
||||
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IDiagnosticsService, isRemoteDiagnosticError, PerformanceInfo, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IDiagnosticsMainService } from 'vs/platform/diagnostics/electron-main/diagnosticsMainService';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterWindowConfiguration, ProcessExplorerData, ProcessExplorerWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IIPCObjectUrl, IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
|
||||
import { zoomLevelToZoomFactor } from 'vs/platform/window/common/window';
|
||||
import { ICodeWindow, IWindowState } from 'vs/platform/window/electron-main/window';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
const processExplorerWindowState = 'issue.processExplorerWindowState';
|
||||
|
||||
interface IBrowserWindowOptions {
|
||||
backgroundColor: string | undefined;
|
||||
title: string;
|
||||
|
@ -50,94 +41,15 @@ export class IssueMainService implements IIssueMainService {
|
|||
private issueReporterWindow: BrowserWindow | null = null;
|
||||
private issueReporterParentWindow: BrowserWindow | null = null;
|
||||
|
||||
private processExplorerWindow: BrowserWindow | null = null;
|
||||
private processExplorerParentWindow: BrowserWindow | null = null;
|
||||
|
||||
constructor(
|
||||
private userEnv: IProcessEnvironment,
|
||||
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService,
|
||||
@IDiagnosticsMainService private readonly diagnosticsMainService: IDiagnosticsMainService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IProtocolMainService private readonly protocolMainService: IProtocolMainService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IStateService private readonly stateService: IStateService,
|
||||
@IWindowsMainService private readonly windowsMainService: IWindowsMainService,
|
||||
) {
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
//#region Register Listeners
|
||||
|
||||
private registerListeners(): void {
|
||||
validatedIpcMain.on('vscode:listProcesses', async event => {
|
||||
const processes = [];
|
||||
|
||||
try {
|
||||
processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(process.pid) });
|
||||
|
||||
const remoteDiagnostics = await this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true });
|
||||
remoteDiagnostics.forEach(data => {
|
||||
if (isRemoteDiagnosticError(data)) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data
|
||||
});
|
||||
} else {
|
||||
if (data.processes) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data.processes
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.logService.error(`Listing processes failed: ${e}`);
|
||||
}
|
||||
|
||||
this.safeSend(event, 'vscode:listProcessesResponse', processes);
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo: { id: any; from: any; args: any }) => {
|
||||
const { id, from, args } = commandInfo;
|
||||
|
||||
let parentWindow: BrowserWindow | null;
|
||||
switch (from) {
|
||||
case 'processExplorer':
|
||||
parentWindow = this.processExplorerParentWindow;
|
||||
break;
|
||||
default:
|
||||
// The issue reporter does not use this anymore.
|
||||
throw new Error(`Unexpected command source: ${from}`);
|
||||
}
|
||||
|
||||
parentWindow?.webContents.send('vscode:runAction', { id, from, args });
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:closeProcessExplorer', event => {
|
||||
this.processExplorerWindow?.close();
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:pidToNameRequest', async event => {
|
||||
const mainProcessInfo = await this.diagnosticsMainService.getMainDiagnostics();
|
||||
|
||||
const pidToNames: [number, string][] = [];
|
||||
for (const window of mainProcessInfo.windows) {
|
||||
pidToNames.push([window.pid, `window [${window.id}] (${window.title})`]);
|
||||
}
|
||||
|
||||
for (const { pid, name } of UtilityProcess.getAll()) {
|
||||
pidToNames.push([pid, name]);
|
||||
}
|
||||
|
||||
this.safeSend(event, 'vscode:pidToNameResponse', pidToNames);
|
||||
});
|
||||
}
|
||||
|
||||
//#endregion
|
||||
) { }
|
||||
|
||||
//#region Used by renderer
|
||||
|
||||
|
@ -196,125 +108,9 @@ export class IssueMainService implements IIssueMainService {
|
|||
}
|
||||
}
|
||||
|
||||
async openProcessExplorer(data: ProcessExplorerData): Promise<void> {
|
||||
if (!this.processExplorerWindow) {
|
||||
this.processExplorerParentWindow = BrowserWindow.getFocusedWindow();
|
||||
if (this.processExplorerParentWindow) {
|
||||
const processExplorerDisposables = new DisposableStore();
|
||||
|
||||
const processExplorerWindowConfigUrl = processExplorerDisposables.add(this.protocolMainService.createIPCObjectUrl<ProcessExplorerWindowConfiguration>());
|
||||
|
||||
const savedPosition = this.stateService.getItem<IWindowState>(processExplorerWindowState, undefined);
|
||||
const position = isStrictWindowState(savedPosition) ? savedPosition : this.getWindowPosition(this.processExplorerParentWindow, 800, 500);
|
||||
|
||||
this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, {
|
||||
backgroundColor: data.styles.backgroundColor,
|
||||
title: localize('processExplorer', "Process Explorer"),
|
||||
zoomLevel: data.zoomLevel,
|
||||
alwaysOnTop: true
|
||||
}, 'process-explorer');
|
||||
|
||||
// Store into config object URL
|
||||
processExplorerWindowConfigUrl.update({
|
||||
appRoot: this.environmentMainService.appRoot,
|
||||
windowId: this.processExplorerWindow.id,
|
||||
userEnv: this.userEnv,
|
||||
data,
|
||||
product
|
||||
});
|
||||
|
||||
this.processExplorerWindow.loadURL(
|
||||
FileAccess.asBrowserUri(`vs/code/electron-sandbox/processExplorer/processExplorer${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
|
||||
);
|
||||
|
||||
this.processExplorerWindow.on('close', () => {
|
||||
this.processExplorerWindow = null;
|
||||
processExplorerDisposables.dispose();
|
||||
});
|
||||
|
||||
this.processExplorerParentWindow.on('close', () => {
|
||||
if (this.processExplorerWindow) {
|
||||
this.processExplorerWindow.close();
|
||||
this.processExplorerWindow = null;
|
||||
|
||||
processExplorerDisposables.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
const storeState = () => {
|
||||
if (!this.processExplorerWindow) {
|
||||
return;
|
||||
}
|
||||
const size = this.processExplorerWindow.getSize();
|
||||
const position = this.processExplorerWindow.getPosition();
|
||||
if (!size || !position) {
|
||||
return;
|
||||
}
|
||||
const state: IWindowState = {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
x: position[0],
|
||||
y: position[1]
|
||||
};
|
||||
this.stateService.setItem(processExplorerWindowState, state);
|
||||
};
|
||||
|
||||
this.processExplorerWindow.on('moved', storeState);
|
||||
this.processExplorerWindow.on('resized', storeState);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.processExplorerWindow) {
|
||||
this.focusWindow(this.processExplorerWindow);
|
||||
}
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<void> {
|
||||
if (!this.environmentMainService.args.trace) {
|
||||
return; // requires tracing to be on
|
||||
}
|
||||
|
||||
const path = await contentTracing.stopRecording(`${randomPath(this.environmentMainService.userHome.fsPath, this.productService.applicationName)}.trace.txt`);
|
||||
|
||||
// Inform user to report an issue
|
||||
await this.dialogMainService.showMessageBox({
|
||||
type: 'info',
|
||||
message: localize('trace.message', "Successfully created the trace file"),
|
||||
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
|
||||
buttons: [localize({ key: 'trace.ok', comment: ['&& denotes a mnemonic'] }, "&&OK")],
|
||||
}, BrowserWindow.getFocusedWindow() ?? undefined);
|
||||
|
||||
// Show item in explorer
|
||||
this.nativeHostMainService.showItemInFolder(undefined, path);
|
||||
}
|
||||
|
||||
async getSystemStatus(): Promise<string> {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
|
||||
|
||||
return this.diagnosticsService.getDiagnostics(info, remoteData);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region used by issue reporter window
|
||||
|
||||
async $getSystemInfo(): Promise<SystemInfo> {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
|
||||
const msg = await this.diagnosticsService.getSystemInfo(info, remoteData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
async $getPerformanceInfo(): Promise<PerformanceInfo> {
|
||||
try {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })]);
|
||||
return await this.diagnosticsService.getPerformanceInfo(info, remoteData);
|
||||
} catch (error) {
|
||||
this.logService.warn('issueService#getPerformanceInfo ', error.message);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async $reloadWithExtensionsDisabled(): Promise<void> {
|
||||
if (this.issueReporterParentWindow) {
|
||||
try {
|
||||
|
@ -389,10 +185,6 @@ export class IssueMainService implements IIssueMainService {
|
|||
this.issueReporterWindow?.close();
|
||||
}
|
||||
|
||||
async closeProcessExplorer(): Promise<void> {
|
||||
this.processExplorerWindow?.close();
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
private focusWindow(window: BrowserWindow): void {
|
||||
|
@ -403,12 +195,6 @@ export class IssueMainService implements IIssueMainService {
|
|||
window.focus();
|
||||
}
|
||||
|
||||
private safeSend(event: IpcMainEvent, channel: string, ...args: unknown[]): void {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send(channel, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
private createBrowserWindow<T>(position: IWindowState, ipcObjectUrl: IIPCObjectUrl<T>, options: IBrowserWindowOptions, windowKind: string): BrowserWindow {
|
||||
const window = new BrowserWindow({
|
||||
fullscreen: false,
|
||||
|
@ -509,15 +295,3 @@ export class IssueMainService implements IIssueMainService {
|
|||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function isStrictWindowState(obj: unknown): obj is IStrictWindowState {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
'x' in obj &&
|
||||
'y' in obj &&
|
||||
'width' in obj &&
|
||||
'height' in obj
|
||||
);
|
||||
}
|
||||
|
|
375
src/vs/platform/issue/electron-main/processMainService.ts
Normal file
375
src/vs/platform/issue/electron-main/processMainService.ts
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions, contentTracing, Display, IpcMainEvent, screen } from 'electron';
|
||||
import { randomPath } from 'vs/base/common/extpath';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
|
||||
import { listProcesses } from 'vs/base/node/ps';
|
||||
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IDiagnosticsService, isRemoteDiagnosticError, PerformanceInfo, SystemInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IDiagnosticsMainService } from 'vs/platform/diagnostics/electron-main/diagnosticsMainService';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { IProcessMainService, ProcessExplorerData, ProcessExplorerWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IIPCObjectUrl, IProtocolMainService } from 'vs/platform/protocol/electron-main/protocol';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
|
||||
import { zoomLevelToZoomFactor } from 'vs/platform/window/common/window';
|
||||
import { IWindowState } from 'vs/platform/window/electron-main/window';
|
||||
|
||||
const processExplorerWindowState = 'issue.processExplorerWindowState';
|
||||
|
||||
interface IBrowserWindowOptions {
|
||||
backgroundColor: string | undefined;
|
||||
title: string;
|
||||
zoomLevel: number;
|
||||
alwaysOnTop: boolean;
|
||||
}
|
||||
|
||||
type IStrictWindowState = Required<Pick<IWindowState, 'x' | 'y' | 'width' | 'height'>>;
|
||||
|
||||
export class ProcessMainService implements IProcessMainService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
|
||||
|
||||
private processExplorerWindow: BrowserWindow | null = null;
|
||||
private processExplorerParentWindow: BrowserWindow | null = null;
|
||||
|
||||
constructor(
|
||||
private userEnv: IProcessEnvironment,
|
||||
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IDiagnosticsService private readonly diagnosticsService: IDiagnosticsService,
|
||||
@IDiagnosticsMainService private readonly diagnosticsMainService: IDiagnosticsMainService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IProtocolMainService private readonly protocolMainService: IProtocolMainService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IStateService private readonly stateService: IStateService,
|
||||
) {
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
//#region Register Listeners
|
||||
|
||||
private registerListeners(): void {
|
||||
validatedIpcMain.on('vscode:listProcesses', async event => {
|
||||
const processes = [];
|
||||
|
||||
try {
|
||||
processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(process.pid) });
|
||||
|
||||
const remoteDiagnostics = await this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true });
|
||||
remoteDiagnostics.forEach(data => {
|
||||
if (isRemoteDiagnosticError(data)) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data
|
||||
});
|
||||
} else {
|
||||
if (data.processes) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data.processes
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.logService.error(`Listing processes failed: ${e}`);
|
||||
}
|
||||
|
||||
this.safeSend(event, 'vscode:listProcessesResponse', processes);
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:workbenchCommand', (_: unknown, commandInfo: { id: any; from: any; args: any }) => {
|
||||
const { id, from, args } = commandInfo;
|
||||
|
||||
let parentWindow: BrowserWindow | null;
|
||||
switch (from) {
|
||||
case 'processExplorer':
|
||||
parentWindow = this.processExplorerParentWindow;
|
||||
break;
|
||||
default:
|
||||
// The issue reporter does not use this anymore.
|
||||
throw new Error(`Unexpected command source: ${from}`);
|
||||
}
|
||||
|
||||
parentWindow?.webContents.send('vscode:runAction', { id, from, args });
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:closeProcessExplorer', event => {
|
||||
this.processExplorerWindow?.close();
|
||||
});
|
||||
|
||||
validatedIpcMain.on('vscode:pidToNameRequest', async event => {
|
||||
const mainProcessInfo = await this.diagnosticsMainService.getMainDiagnostics();
|
||||
|
||||
const pidToNames: [number, string][] = [];
|
||||
for (const window of mainProcessInfo.windows) {
|
||||
pidToNames.push([window.pid, `window [${window.id}] (${window.title})`]);
|
||||
}
|
||||
|
||||
for (const { pid, name } of UtilityProcess.getAll()) {
|
||||
pidToNames.push([pid, name]);
|
||||
}
|
||||
|
||||
this.safeSend(event, 'vscode:pidToNameResponse', pidToNames);
|
||||
});
|
||||
}
|
||||
|
||||
async openProcessExplorer(data: ProcessExplorerData): Promise<void> {
|
||||
if (!this.processExplorerWindow) {
|
||||
this.processExplorerParentWindow = BrowserWindow.getFocusedWindow();
|
||||
if (this.processExplorerParentWindow) {
|
||||
const processExplorerDisposables = new DisposableStore();
|
||||
|
||||
const processExplorerWindowConfigUrl = processExplorerDisposables.add(this.protocolMainService.createIPCObjectUrl<ProcessExplorerWindowConfiguration>());
|
||||
|
||||
const savedPosition = this.stateService.getItem<IWindowState>(processExplorerWindowState, undefined);
|
||||
const position = isStrictWindowState(savedPosition) ? savedPosition : this.getWindowPosition(this.processExplorerParentWindow, 800, 500);
|
||||
|
||||
this.processExplorerWindow = this.createBrowserWindow(position, processExplorerWindowConfigUrl, {
|
||||
backgroundColor: data.styles.backgroundColor,
|
||||
title: localize('processExplorer', "Process Explorer"),
|
||||
zoomLevel: data.zoomLevel,
|
||||
alwaysOnTop: true
|
||||
}, 'process-explorer');
|
||||
|
||||
// Store into config object URL
|
||||
processExplorerWindowConfigUrl.update({
|
||||
appRoot: this.environmentMainService.appRoot,
|
||||
windowId: this.processExplorerWindow.id,
|
||||
userEnv: this.userEnv,
|
||||
data,
|
||||
product
|
||||
});
|
||||
|
||||
this.processExplorerWindow.loadURL(
|
||||
FileAccess.asBrowserUri(`vs/code/electron-sandbox/processExplorer/processExplorer${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true)
|
||||
);
|
||||
|
||||
this.processExplorerWindow.on('close', () => {
|
||||
this.processExplorerWindow = null;
|
||||
processExplorerDisposables.dispose();
|
||||
});
|
||||
|
||||
this.processExplorerParentWindow.on('close', () => {
|
||||
if (this.processExplorerWindow) {
|
||||
this.processExplorerWindow.close();
|
||||
this.processExplorerWindow = null;
|
||||
|
||||
processExplorerDisposables.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
const storeState = () => {
|
||||
if (!this.processExplorerWindow) {
|
||||
return;
|
||||
}
|
||||
const size = this.processExplorerWindow.getSize();
|
||||
const position = this.processExplorerWindow.getPosition();
|
||||
if (!size || !position) {
|
||||
return;
|
||||
}
|
||||
const state: IWindowState = {
|
||||
width: size[0],
|
||||
height: size[1],
|
||||
x: position[0],
|
||||
y: position[1]
|
||||
};
|
||||
this.stateService.setItem(processExplorerWindowState, state);
|
||||
};
|
||||
|
||||
this.processExplorerWindow.on('moved', storeState);
|
||||
this.processExplorerWindow.on('resized', storeState);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.processExplorerWindow) {
|
||||
this.focusWindow(this.processExplorerWindow);
|
||||
}
|
||||
}
|
||||
|
||||
private focusWindow(window: BrowserWindow): void {
|
||||
if (window.isMinimized()) {
|
||||
window.restore();
|
||||
}
|
||||
|
||||
window.focus();
|
||||
}
|
||||
|
||||
private getWindowPosition(parentWindow: BrowserWindow, defaultWidth: number, defaultHeight: number): IStrictWindowState {
|
||||
|
||||
// We want the new window to open on the same display that the parent is in
|
||||
let displayToUse: Display | undefined;
|
||||
const displays = screen.getAllDisplays();
|
||||
|
||||
// Single Display
|
||||
if (displays.length === 1) {
|
||||
displayToUse = displays[0];
|
||||
}
|
||||
|
||||
// Multi Display
|
||||
else {
|
||||
|
||||
// on mac there is 1 menu per window so we need to use the monitor where the cursor currently is
|
||||
if (isMacintosh) {
|
||||
const cursorPoint = screen.getCursorScreenPoint();
|
||||
displayToUse = screen.getDisplayNearestPoint(cursorPoint);
|
||||
}
|
||||
|
||||
// if we have a last active window, use that display for the new window
|
||||
if (!displayToUse && parentWindow) {
|
||||
displayToUse = screen.getDisplayMatching(parentWindow.getBounds());
|
||||
}
|
||||
|
||||
// fallback to primary display or first display
|
||||
if (!displayToUse) {
|
||||
displayToUse = screen.getPrimaryDisplay() || displays[0];
|
||||
}
|
||||
}
|
||||
|
||||
const displayBounds = displayToUse.bounds;
|
||||
|
||||
const state: IStrictWindowState = {
|
||||
width: defaultWidth,
|
||||
height: defaultHeight,
|
||||
x: displayBounds.x + (displayBounds.width / 2) - (defaultWidth / 2),
|
||||
y: displayBounds.y + (displayBounds.height / 2) - (defaultHeight / 2)
|
||||
};
|
||||
|
||||
if (displayBounds.width > 0 && displayBounds.height > 0 /* Linux X11 sessions sometimes report wrong display bounds */) {
|
||||
if (state.x < displayBounds.x) {
|
||||
state.x = displayBounds.x; // prevent window from falling out of the screen to the left
|
||||
}
|
||||
|
||||
if (state.y < displayBounds.y) {
|
||||
state.y = displayBounds.y; // prevent window from falling out of the screen to the top
|
||||
}
|
||||
|
||||
if (state.x > (displayBounds.x + displayBounds.width)) {
|
||||
state.x = displayBounds.x; // prevent window from falling out of the screen to the right
|
||||
}
|
||||
|
||||
if (state.y > (displayBounds.y + displayBounds.height)) {
|
||||
state.y = displayBounds.y; // prevent window from falling out of the screen to the bottom
|
||||
}
|
||||
|
||||
if (state.width > displayBounds.width) {
|
||||
state.width = displayBounds.width; // prevent window from exceeding display bounds width
|
||||
}
|
||||
|
||||
if (state.height > displayBounds.height) {
|
||||
state.height = displayBounds.height; // prevent window from exceeding display bounds height
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
async stopTracing(): Promise<void> {
|
||||
if (!this.environmentMainService.args.trace) {
|
||||
return; // requires tracing to be on
|
||||
}
|
||||
|
||||
const path = await contentTracing.stopRecording(`${randomPath(this.environmentMainService.userHome.fsPath, this.productService.applicationName)}.trace.txt`);
|
||||
|
||||
// Inform user to report an issue
|
||||
await this.dialogMainService.showMessageBox({
|
||||
type: 'info',
|
||||
message: localize('trace.message', "Successfully created the trace file"),
|
||||
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
|
||||
buttons: [localize({ key: 'trace.ok', comment: ['&& denotes a mnemonic'] }, "&&OK")],
|
||||
}, BrowserWindow.getFocusedWindow() ?? undefined);
|
||||
|
||||
// Show item in explorer
|
||||
this.nativeHostMainService.showItemInFolder(undefined, path);
|
||||
}
|
||||
|
||||
async getSystemStatus(): Promise<string> {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
|
||||
return this.diagnosticsService.getDiagnostics(info, remoteData);
|
||||
}
|
||||
|
||||
async $getSystemInfo(): Promise<SystemInfo> {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })]);
|
||||
const msg = await this.diagnosticsService.getSystemInfo(info, remoteData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
async $getPerformanceInfo(): Promise<PerformanceInfo> {
|
||||
try {
|
||||
const [info, remoteData] = await Promise.all([this.diagnosticsMainService.getMainDiagnostics(), this.diagnosticsMainService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true })]);
|
||||
return await this.diagnosticsService.getPerformanceInfo(info, remoteData);
|
||||
} catch (error) {
|
||||
this.logService.warn('issueService#getPerformanceInfo ', error.message);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private createBrowserWindow<T>(position: IWindowState, ipcObjectUrl: IIPCObjectUrl<T>, options: IBrowserWindowOptions, windowKind: string): BrowserWindow {
|
||||
const window = new BrowserWindow({
|
||||
fullscreen: false,
|
||||
skipTaskbar: false,
|
||||
resizable: true,
|
||||
width: position.width,
|
||||
height: position.height,
|
||||
minWidth: 300,
|
||||
minHeight: 200,
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
title: options.title,
|
||||
backgroundColor: options.backgroundColor || ProcessMainService.DEFAULT_BACKGROUND_COLOR,
|
||||
webPreferences: {
|
||||
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-sandbox/preload.js').fsPath,
|
||||
additionalArguments: [`--vscode-window-config=${ipcObjectUrl.resource.toString()}`],
|
||||
v8CacheOptions: this.environmentMainService.useCodeCache ? 'bypassHeatCheck' : 'none',
|
||||
enableWebSQL: false,
|
||||
spellcheck: false,
|
||||
zoomFactor: zoomLevelToZoomFactor(options.zoomLevel),
|
||||
sandbox: true
|
||||
},
|
||||
alwaysOnTop: options.alwaysOnTop,
|
||||
experimentalDarkMode: true
|
||||
} as BrowserWindowConstructorOptions & { experimentalDarkMode: boolean });
|
||||
|
||||
window.setMenuBarVisibility(false);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
private safeSend(event: IpcMainEvent, channel: string, ...args: unknown[]): void {
|
||||
if (!event.sender.isDestroyed()) {
|
||||
event.sender.send(channel, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
async closeProcessExplorer(): Promise<void> {
|
||||
this.processExplorerWindow?.close();
|
||||
}
|
||||
}
|
||||
|
||||
function isStrictWindowState(obj: unknown): obj is IStrictWindowState {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
'x' in obj &&
|
||||
'y' in obj &&
|
||||
'width' in obj &&
|
||||
'height' in obj
|
||||
);
|
||||
}
|
|
@ -240,26 +240,6 @@ export class BaseIssueReporterService extends Disposable {
|
|||
}
|
||||
|
||||
public setEventHandlers(): void {
|
||||
this.addEventListener('issue-type', 'change', (event: Event) => {
|
||||
const issueType = parseInt((<HTMLInputElement>event.target).value);
|
||||
this.issueReporterModel.update({ issueType: issueType });
|
||||
if (issueType === IssueType.PerformanceIssue && !this.receivedPerformanceInfo) {
|
||||
this.issueMainService.$getPerformanceInfo().then(info => {
|
||||
this.updatePerformanceInfo(info as Partial<IssueReporterData>);
|
||||
});
|
||||
}
|
||||
|
||||
// Resets placeholder
|
||||
const descriptionTextArea = <HTMLInputElement>this.getElementById('issue-title');
|
||||
if (descriptionTextArea) {
|
||||
descriptionTextArea.placeholder = localize('undefinedPlaceholder', "Please enter a title");
|
||||
}
|
||||
|
||||
this.updatePreviewButtonState();
|
||||
this.setSourceOptions();
|
||||
this.render();
|
||||
});
|
||||
|
||||
(['includeSystemInfo', 'includeProcessInfo', 'includeWorkspaceInfo', 'includeExtensions', 'includeExperiments', 'includeExtensionData'] as const).forEach(elementId => {
|
||||
this.addEventListener(elementId, 'click', (event: Event) => {
|
||||
event.stopPropagation();
|
||||
|
|
|
@ -72,6 +72,20 @@ export class IssueWebReporter extends BaseIssueReporterService {
|
|||
|
||||
public override setEventHandlers(): void {
|
||||
super.setEventHandlers();
|
||||
this.addEventListener('issue-type', 'change', (event: Event) => {
|
||||
const issueType = parseInt((<HTMLInputElement>event.target).value);
|
||||
this.issueReporterModel.update({ issueType: issueType });
|
||||
|
||||
// Resets placeholder
|
||||
const descriptionTextArea = <HTMLInputElement>this.getElementById('issue-title');
|
||||
if (descriptionTextArea) {
|
||||
descriptionTextArea.placeholder = localize('undefinedPlaceholder', "Please enter a title");
|
||||
}
|
||||
|
||||
this.updatePreviewButtonState();
|
||||
this.setSourceOptions();
|
||||
this.render();
|
||||
});
|
||||
this.previewButton.onDidClick(async () => {
|
||||
this.delayedSubmit.trigger(async () => {
|
||||
this.createIssue();
|
||||
|
|
|
@ -10,5 +10,12 @@ export const IWorkbenchIssueService = createDecorator<IWorkbenchIssueService>('w
|
|||
export interface IWorkbenchIssueService {
|
||||
readonly _serviceBrand: undefined;
|
||||
openReporter(dataOverrides?: Partial<IssueReporterData>): Promise<void>;
|
||||
}
|
||||
|
||||
export const IWorkbenchProcessService = createDecorator<IWorkbenchProcessService>('workbenchProcessService');
|
||||
|
||||
export interface IWorkbenchProcessService {
|
||||
readonly _serviceBrand: undefined;
|
||||
openProcessExplorer(): Promise<void>;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize, localize2 } from 'vs/nls';
|
||||
import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { BaseIssueContribution } from 'vs/workbench/contrib/issue/common/issue.contribution';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
@ -14,11 +13,7 @@ import { Extensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common
|
|||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IIssueMainService, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess';
|
||||
|
@ -27,7 +22,6 @@ import 'vs/workbench/contrib/issue/electron-sandbox/issueMainService';
|
|||
import 'vs/workbench/contrib/issue/electron-sandbox/issueService';
|
||||
import 'vs/workbench/contrib/issue/browser/issueTroubleshoot';
|
||||
|
||||
|
||||
//#region Issue Contribution
|
||||
|
||||
class NativeIssueContribution extends BaseIssueContribution {
|
||||
|
@ -87,87 +81,10 @@ class ReportPerformanceIssueUsingReporterAction extends Action2 {
|
|||
}
|
||||
|
||||
override async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const issueService = accessor.get(IWorkbenchIssueService);
|
||||
const issueService = accessor.get(IWorkbenchIssueService); // later can just get IIssueFormService
|
||||
|
||||
return issueService.openReporter({ issueType: IssueType.PerformanceIssue });
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Commands
|
||||
|
||||
class OpenProcessExplorer extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.openProcessExplorer';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: OpenProcessExplorer.ID,
|
||||
title: localize2('openProcessExplorer', 'Open Process Explorer'),
|
||||
category: Categories.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const issueService = accessor.get(IWorkbenchIssueService);
|
||||
|
||||
return issueService.openProcessExplorer();
|
||||
}
|
||||
}
|
||||
registerAction2(OpenProcessExplorer);
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: OpenProcessExplorer.ID,
|
||||
title: localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
class StopTracing extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.stopTracing';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: StopTracing.ID,
|
||||
title: localize2('stopTracing', 'Stop Tracing'),
|
||||
category: Categories.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const issueService = accessor.get(IIssueMainService);
|
||||
const environmentService = accessor.get(INativeEnvironmentService);
|
||||
const dialogService = accessor.get(IDialogService);
|
||||
const nativeHostService = accessor.get(INativeHostService);
|
||||
const progressService = accessor.get(IProgressService);
|
||||
|
||||
if (!environmentService.args.trace) {
|
||||
const { confirmed } = await dialogService.confirm({
|
||||
message: localize('stopTracing.message', "Tracing requires to launch with a '--trace' argument"),
|
||||
primaryButton: localize({ key: 'stopTracing.button', comment: ['&& denotes a mnemonic'] }, "&&Relaunch and Enable Tracing"),
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
return nativeHostService.relaunch({ addArgs: ['--trace'] });
|
||||
}
|
||||
}
|
||||
|
||||
await progressService.withProgress({
|
||||
location: ProgressLocation.Dialog,
|
||||
title: localize('stopTracing.title', "Creating trace file..."),
|
||||
cancellable: false,
|
||||
detail: localize('stopTracing.detail', "This can take up to one minute to complete.")
|
||||
}, () => issueService.stopTracing());
|
||||
}
|
||||
}
|
||||
registerAction2(StopTracing);
|
||||
|
||||
CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => {
|
||||
return accessor.get(IIssueMainService).getSystemStatus();
|
||||
});
|
||||
//#endregion
|
||||
// #endregion
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { IIssueMainService } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IProcessMainService } from 'vs/platform/issue/common/issue';
|
||||
|
||||
registerMainProcessRemoteService(IIssueMainService, 'issue');
|
||||
registerMainProcessRemoteService(IProcessMainService, 'process');
|
||||
|
||||
|
|
|
@ -15,12 +15,13 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||
import { IMainProcessService } from 'vs/platform/ipc/common/mainProcessService';
|
||||
import { ElectronIPCMainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { IIssueMainService, IssueReporterWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IProcessMainService, IssueReporterWindowConfiguration } from 'vs/platform/issue/common/issue';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { NativeHostService } from 'vs/platform/native/common/nativeHostService';
|
||||
import { IssueReporter2 } from 'vs/workbench/contrib/issue/electron-sandbox/issueReporterService2';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
|
||||
|
||||
export function startup(configuration: IssueReporterWindowConfiguration) {
|
||||
const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac';
|
||||
mainWindow.document.body.classList.add(platformClass); // used by our fonts
|
||||
|
@ -50,3 +51,4 @@ function initServices(windowId: number) {
|
|||
}
|
||||
|
||||
registerMainProcessRemoteService(IIssueMainService, 'issue');
|
||||
registerMainProcessRemoteService(IProcessMainService, 'process');
|
||||
|
|
|
@ -19,7 +19,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/workbench/contrib/issue/browser/issueReporterModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IProcessMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { normalizeGitHubUrl } from 'vs/platform/issue/common/issueReporterUtil';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { getIconsStyleSheet } from 'vs/platform/theme/browser/iconsStyleSheet';
|
||||
|
@ -59,7 +59,8 @@ export class IssueReporter extends Disposable {
|
|||
constructor(
|
||||
private readonly configuration: IssueReporterWindowConfiguration,
|
||||
@INativeHostService private readonly nativeHostService: INativeHostService,
|
||||
@IIssueMainService private readonly issueMainService: IIssueMainService
|
||||
@IIssueMainService private readonly issueMainService: IIssueMainService,
|
||||
@IProcessMainService private readonly processMainService: IProcessMainService
|
||||
) {
|
||||
super();
|
||||
const targetExtension = configuration.data.extensionId ? configuration.data.enabledExtensions.find(extension => extension.id.toLocaleLowerCase() === configuration.data.extensionId?.toLocaleLowerCase()) : undefined;
|
||||
|
@ -107,7 +108,7 @@ export class IssueReporter extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
this.issueMainService.$getSystemInfo().then(info => {
|
||||
this.processMainService.$getSystemInfo().then(info => {
|
||||
this.issueReporterModel.update({ systemInfo: info });
|
||||
this.receivedSystemInfo = true;
|
||||
|
||||
|
@ -115,7 +116,7 @@ export class IssueReporter extends Disposable {
|
|||
this.updatePreviewButtonState();
|
||||
});
|
||||
if (configuration.data.issueType === IssueType.PerformanceIssue) {
|
||||
this.issueMainService.$getPerformanceInfo().then(info => {
|
||||
this.processMainService.$getPerformanceInfo().then(info => {
|
||||
this.updatePerformanceInfo(info as Partial<IssueReporterData>);
|
||||
});
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ export class IssueReporter extends Disposable {
|
|||
const issueType = parseInt((<HTMLInputElement>event.target).value);
|
||||
this.issueReporterModel.update({ issueType: issueType });
|
||||
if (issueType === IssueType.PerformanceIssue && !this.receivedPerformanceInfo) {
|
||||
this.issueMainService.$getPerformanceInfo().then(info => {
|
||||
this.processMainService.$getPerformanceInfo().then(info => {
|
||||
this.updatePerformanceInfo(info as Partial<IssueReporterData>);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ThemeIcon } from 'vs/base/common/themables';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { IIssueMainService, IProcessMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterWindowConfiguration, IssueType } from 'vs/platform/issue/common/issue';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/window/electron-sandbox/window';
|
||||
import { BaseIssueReporterService, hide, show } from 'vs/workbench/contrib/issue/browser/issue';
|
||||
|
@ -24,14 +24,17 @@ const MAX_URL_LENGTH = 7500;
|
|||
|
||||
|
||||
export class IssueReporter2 extends BaseIssueReporterService {
|
||||
private readonly processMainService: IProcessMainService;
|
||||
constructor(
|
||||
private readonly configuration: IssueReporterWindowConfiguration,
|
||||
@INativeHostService private readonly nativeHostService: INativeHostService,
|
||||
@IIssueMainService issueMainService: IIssueMainService
|
||||
@IIssueMainService issueMainService: IIssueMainService,
|
||||
@IProcessMainService processMainService: IProcessMainService
|
||||
) {
|
||||
super(configuration.disableExtensions, configuration.data, configuration.os, configuration.product, mainWindow, false, issueMainService);
|
||||
|
||||
this.issueMainService.$getSystemInfo().then(info => {
|
||||
this.processMainService = processMainService;
|
||||
this.processMainService.$getSystemInfo().then(info => {
|
||||
this.issueReporterModel.update({ systemInfo: info });
|
||||
this.receivedSystemInfo = true;
|
||||
|
||||
|
@ -39,7 +42,7 @@ export class IssueReporter2 extends BaseIssueReporterService {
|
|||
this.updatePreviewButtonState();
|
||||
});
|
||||
if (configuration.data.issueType === IssueType.PerformanceIssue) {
|
||||
this.issueMainService.$getPerformanceInfo().then(info => {
|
||||
this.processMainService.$getPerformanceInfo().then(info => {
|
||||
this.updatePerformanceInfo(info as Partial<IssueReporterData>);
|
||||
});
|
||||
}
|
||||
|
@ -81,6 +84,26 @@ export class IssueReporter2 extends BaseIssueReporterService {
|
|||
public override setEventHandlers(): void {
|
||||
super.setEventHandlers();
|
||||
|
||||
this.addEventListener('issue-type', 'change', (event: Event) => {
|
||||
const issueType = parseInt((<HTMLInputElement>event.target).value);
|
||||
this.issueReporterModel.update({ issueType: issueType });
|
||||
if (issueType === IssueType.PerformanceIssue && !this.receivedPerformanceInfo) {
|
||||
this.processMainService.$getPerformanceInfo().then(info => {
|
||||
this.updatePerformanceInfo(info as Partial<IssueReporterData>);
|
||||
});
|
||||
}
|
||||
|
||||
// Resets placeholder
|
||||
const descriptionTextArea = <HTMLInputElement>this.getElementById('issue-title');
|
||||
if (descriptionTextArea) {
|
||||
descriptionTextArea.placeholder = localize('undefinedPlaceholder', "Please enter a title");
|
||||
}
|
||||
|
||||
this.updatePreviewButtonState();
|
||||
this.setSourceOptions();
|
||||
this.render();
|
||||
});
|
||||
|
||||
// Keep all event listerns involving window and issue creation
|
||||
this.previewButton.onDidClick(async () => {
|
||||
this.delayedSubmit.trigger(async () => {
|
||||
|
|
|
@ -4,20 +4,17 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
import { platform } from 'vs/base/common/process';
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionIdentifier, ExtensionType, ExtensionIdentifierSet } from 'vs/platform/extensions/common/extensions';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { activeContrastBorder, buttonBackground, buttonForeground, buttonHoverBackground, editorBackground, editorForeground, foreground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, listActiveSelectionBackground, listActiveSelectionForeground, listFocusBackground, listFocusForeground, listFocusOutline, listHoverBackground, listHoverForeground, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IIssueMainService, IssueReporterData, IssueReporterExtensionData, IssueReporterStyles } from 'vs/platform/issue/common/issue';
|
||||
import { buttonBackground, buttonForeground, buttonHoverBackground, foreground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
|
||||
import { IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
|
||||
import { IWorkbenchIssueService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
|
@ -34,9 +31,7 @@ export class NativeIssueService implements IWorkbenchIssueService {
|
|||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
@IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
|
||||
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,
|
||||
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
|
||||
@IIntegrityService private readonly integrityService: IIntegrityService,
|
||||
|
@ -153,34 +148,6 @@ export class NativeIssueService implements IWorkbenchIssueService {
|
|||
return this.issueMainService.openReporter(issueReporterData);
|
||||
}
|
||||
|
||||
openProcessExplorer(): Promise<void> {
|
||||
const theme = this.themeService.getColorTheme();
|
||||
const data: ProcessExplorerData = {
|
||||
pid: this.environmentService.mainPid,
|
||||
zoomLevel: getZoomLevel(mainWindow),
|
||||
styles: {
|
||||
backgroundColor: getColor(theme, editorBackground),
|
||||
color: getColor(theme, editorForeground),
|
||||
listHoverBackground: getColor(theme, listHoverBackground),
|
||||
listHoverForeground: getColor(theme, listHoverForeground),
|
||||
listFocusBackground: getColor(theme, listFocusBackground),
|
||||
listFocusForeground: getColor(theme, listFocusForeground),
|
||||
listFocusOutline: getColor(theme, listFocusOutline),
|
||||
listActiveSelectionBackground: getColor(theme, listActiveSelectionBackground),
|
||||
listActiveSelectionForeground: getColor(theme, listActiveSelectionForeground),
|
||||
listHoverOutline: getColor(theme, activeContrastBorder),
|
||||
scrollbarShadowColor: getColor(theme, scrollbarShadow),
|
||||
scrollbarSliderActiveBackgroundColor: getColor(theme, scrollbarSliderActiveBackground),
|
||||
scrollbarSliderBackgroundColor: getColor(theme, scrollbarSliderBackground),
|
||||
scrollbarSliderHoverBackgroundColor: getColor(theme, scrollbarSliderHoverBackground),
|
||||
},
|
||||
platform: platform,
|
||||
applicationName: this.productService.applicationName
|
||||
};
|
||||
return this.issueMainService.openProcessExplorer(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export function getIssueReporterStyles(theme: IColorTheme): IssueReporterStyles {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize, localize2 } from 'vs/nls';
|
||||
import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchProcessService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INativeHostService } from 'vs/platform/native/common/native';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IProcessMainService } from 'vs/platform/issue/common/issue';
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/processService';
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/issueMainService';
|
||||
|
||||
|
||||
//#region Commands
|
||||
|
||||
class OpenProcessExplorer extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.openProcessExplorer';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: OpenProcessExplorer.ID,
|
||||
title: localize2('openProcessExplorer', 'Open Process Explorer'),
|
||||
category: Categories.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const processService = accessor.get(IWorkbenchProcessService);
|
||||
|
||||
return processService.openProcessExplorer();
|
||||
}
|
||||
}
|
||||
registerAction2(OpenProcessExplorer);
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: OpenProcessExplorer.ID,
|
||||
title: localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
class StopTracing extends Action2 {
|
||||
|
||||
static readonly ID = 'workbench.action.stopTracing';
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: StopTracing.ID,
|
||||
title: localize2('stopTracing', 'Stop Tracing'),
|
||||
category: Categories.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
override async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const processService = accessor.get(IProcessMainService);
|
||||
const environmentService = accessor.get(INativeEnvironmentService);
|
||||
const dialogService = accessor.get(IDialogService);
|
||||
const nativeHostService = accessor.get(INativeHostService);
|
||||
const progressService = accessor.get(IProgressService);
|
||||
|
||||
if (!environmentService.args.trace) {
|
||||
const { confirmed } = await dialogService.confirm({
|
||||
message: localize('stopTracing.message', "Tracing requires to launch with a '--trace' argument"),
|
||||
primaryButton: localize({ key: 'stopTracing.button', comment: ['&& denotes a mnemonic'] }, "&&Relaunch and Enable Tracing"),
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
return nativeHostService.relaunch({ addArgs: ['--trace'] });
|
||||
}
|
||||
}
|
||||
|
||||
await progressService.withProgress({
|
||||
location: ProgressLocation.Dialog,
|
||||
title: localize('stopTracing.title', "Creating trace file..."),
|
||||
cancellable: false,
|
||||
detail: localize('stopTracing.detail', "This can take up to one minute to complete.")
|
||||
}, () => processService.stopTracing());
|
||||
}
|
||||
}
|
||||
registerAction2(StopTracing);
|
||||
|
||||
CommandsRegistry.registerCommand('_issues.getSystemStatus', (accessor) => {
|
||||
return accessor.get(IProcessMainService).getSystemStatus();
|
||||
});
|
||||
//#endregion
|
|
@ -0,0 +1,62 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { getZoomLevel } from 'vs/base/browser/browser';
|
||||
import { platform } from 'vs/base/common/process';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IProcessMainService, ProcessExplorerData } from 'vs/platform/issue/common/issue';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { activeContrastBorder, editorBackground, editorForeground, listActiveSelectionBackground, listActiveSelectionForeground, listFocusBackground, listFocusForeground, listFocusOutline, listHoverBackground, listHoverForeground, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IWorkbenchProcessService } from 'vs/workbench/contrib/issue/common/issue';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
|
||||
export class ProcessService implements IWorkbenchProcessService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IProcessMainService private readonly processMainService: IProcessMainService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
) { }
|
||||
|
||||
openProcessExplorer(): Promise<void> {
|
||||
const theme = this.themeService.getColorTheme();
|
||||
const data: ProcessExplorerData = {
|
||||
pid: this.environmentService.mainPid,
|
||||
zoomLevel: getZoomLevel(mainWindow),
|
||||
styles: {
|
||||
backgroundColor: getColor(theme, editorBackground),
|
||||
color: getColor(theme, editorForeground),
|
||||
listHoverBackground: getColor(theme, listHoverBackground),
|
||||
listHoverForeground: getColor(theme, listHoverForeground),
|
||||
listFocusBackground: getColor(theme, listFocusBackground),
|
||||
listFocusForeground: getColor(theme, listFocusForeground),
|
||||
listFocusOutline: getColor(theme, listFocusOutline),
|
||||
listActiveSelectionBackground: getColor(theme, listActiveSelectionBackground),
|
||||
listActiveSelectionForeground: getColor(theme, listActiveSelectionForeground),
|
||||
listHoverOutline: getColor(theme, activeContrastBorder),
|
||||
scrollbarShadowColor: getColor(theme, scrollbarShadow),
|
||||
scrollbarSliderActiveBackgroundColor: getColor(theme, scrollbarSliderActiveBackground),
|
||||
scrollbarSliderBackgroundColor: getColor(theme, scrollbarSliderBackground),
|
||||
scrollbarSliderHoverBackgroundColor: getColor(theme, scrollbarSliderHoverBackground),
|
||||
},
|
||||
platform: platform,
|
||||
applicationName: this.productService.applicationName
|
||||
};
|
||||
return this.processMainService.openProcessExplorer(data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function getColor(theme: IColorTheme, key: string): string | undefined {
|
||||
const color = theme.getColor(key);
|
||||
return color ? color.toString() : undefined;
|
||||
}
|
||||
|
||||
registerSingleton(IWorkbenchProcessService, ProcessService, InstantiationType.Delayed);
|
|
@ -118,6 +118,9 @@ import 'vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution
|
|||
// Issues
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/issue.contribution';
|
||||
|
||||
// Process
|
||||
import 'vs/workbench/contrib/issue/electron-sandbox/process.contribution';
|
||||
|
||||
// Remote
|
||||
import 'vs/workbench/contrib/remote/electron-sandbox/remote.contribution';
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ import 'vs/workbench/contrib/tags/browser/workspaceTagsService';
|
|||
// Issues
|
||||
import 'vs/workbench/contrib/issue/browser/issue.contribution';
|
||||
|
||||
|
||||
// Splash
|
||||
import 'vs/workbench/contrib/splash/browser/splash.contribution';
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user