Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -3,11 +3,9 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/processExplorer';
import { listProcesses, ProcessItem } from 'vs/base/node/ps';
import { remote, webFrame, ipcRenderer, clipboard } from 'electron';
import { webFrame, ipcRenderer, clipboard } from 'electron';
import { repeat } from 'vs/base/common/strings';
import { totalmem } from 'os';
import product from 'vs/platform/node/product';
@@ -15,10 +13,15 @@ import { localize } from 'vs/nls';
import { ProcessExplorerStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import * as browser from 'vs/base/browser/browser';
import * as platform from 'vs/base/common/platform';
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
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;
@@ -77,16 +114,24 @@ function getProcessIdWithHighestProperty(processList, propertyName: string) {
function updateProcessInfo(processList): void {
const target = document.getElementById('process-list');
if (!target) {
return;
}
const highestCPUProcess = getProcessIdWithHighestProperty(processList, 'cpu');
const highestMemoryProcess = getProcessIdWithHighestProperty(processList, 'memory');
let tableHtml = `
<tr>
<th class="cpu">${localize('cpu', "CPU %")}</th>
<th class="memory">${localize('memory', "Memory (MB)")}</th>
<th class="pid">${localize('pid', "pid")}</th>
<th class="nameLabel">${localize('name', "Name")}</th>
</tr>`;
<thead>
<tr>
<th scope="col" class="cpu">${localize('cpu', "CPU %")}</th>
<th scope="col" class="memory">${localize('memory', "Memory (MB)")}</th>
<th scope="col" class="pid">${localize('pid', "pid")}</th>
<th scope="col" class="nameLabel">${localize('name', "Name")}</th>
</tr>
</thead>`;
tableHtml += `<tbody>`;
processList.forEach(p => {
const cpuClass = p.pid === highestCPUProcess ? 'highest' : '';
@@ -101,7 +146,9 @@ function updateProcessInfo(processList): void {
</tr>`;
});
target.innerHTML = `<table>${tableHtml}</table>`;
tableHtml += `</tbody>`;
target.innerHTML = tableHtml;
}
function applyStyles(styles: ProcessExplorerStyles): void {
@@ -121,7 +168,9 @@ function applyStyles(styles: ProcessExplorerStyles): void {
}
styleTag.innerHTML = content.join('\n');
document.head.appendChild(styleTag);
if (document.head) {
document.head.appendChild(styleTag);
}
document.body.style.color = styles.color;
}
@@ -137,29 +186,29 @@ function applyZoom(zoomLevel: number): void {
function showContextMenu(e) {
e.preventDefault();
const menu = new remote.Menu();
const items: IContextMenuItem[] = [];
const pid = parseInt(e.currentTarget.id);
if (pid && typeof pid === 'number') {
menu.append(new remote.MenuItem({
items.push({
label: localize('killProcess', "Kill Process"),
click() {
process.kill(pid, 'SIGTERM');
}
}));
});
menu.append(new remote.MenuItem({
items.push({
label: localize('forceKillProcess', "Force Kill Process"),
click() {
process.kill(pid, 'SIGKILL');
}
}));
});
menu.append(new remote.MenuItem({
items.push({
type: 'separator'
}));
});
menu.append(new remote.MenuItem({
items.push({
label: localize('copy', "Copy"),
click() {
const row = document.getElementById(pid.toString());
@@ -167,9 +216,9 @@ function showContextMenu(e) {
clipboard.writeText(row.innerText);
}
}
}));
});
menu.append(new remote.MenuItem({
items.push({
label: localize('copyAll', "Copy All"),
click() {
const processList = document.getElementById('process-list');
@@ -177,9 +226,23 @@ function showContextMenu(e) {
clipboard.writeText(processList.innerText);
}
}
}));
});
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 {
menu.append(new remote.MenuItem({
items.push({
label: localize('copyAll', "Copy All"),
click() {
const processList = document.getElementById('process-list');
@@ -187,10 +250,10 @@ function showContextMenu(e) {
clipboard.writeText(processList.innerText);
}
}
}));
});
}
menu.popup({ window: remote.getCurrentWindow() });
popup(items);
}
export function startup(data: ProcessExplorerData): void {
@@ -198,7 +261,7 @@ export function startup(data: ProcessExplorerData): void {
applyZoom(data.zoomLevel);
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
ipcRenderer.on('windowsInfoResponse', (event, windows) => {
ipcRenderer.on('vscode:windowsInfoResponse', (event, windows) => {
mapPidToWindowTitle = new Map<number, string>();
windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
});
@@ -206,7 +269,7 @@ export function startup(data: ProcessExplorerData): void {
setInterval(() => {
ipcRenderer.send('windowsInfoRequest');
listProcesses(remote.process.pid).then(processes => {
listProcesses(data.pid).then(processes => {
processList = getProcessList(processes);
updateProcessInfo(processList);