mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-31 17:23:31 -05:00
Merge from vscode 0a7364f00514c46c9caceece15e1f82f82e3712f
This commit is contained in:
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>
|
||||
|
After Width: | Height: | Size: 139 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M11 10H5.344L11 4.414V10z"/></svg>
|
||||
|
After Width: | Height: | Size: 118 B |
@@ -0,0 +1,106 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
html {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Font Families (with CJK support) */
|
||||
|
||||
.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
|
||||
.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
|
||||
.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
|
||||
.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; }
|
||||
|
||||
.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
|
||||
.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
|
||||
.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
|
||||
.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
|
||||
.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
|
||||
|
||||
/* Linux: add `system-ui` as first font and not `Ubuntu` to allow other distribution pick their standard OS font */
|
||||
.linux { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
|
||||
.linux:lang(zh-Hans) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(zh-Hant) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ja) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ko) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.cpu {
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.pid {
|
||||
width: 50px
|
||||
}
|
||||
|
||||
.memory {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.process-item {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
th[scope='col'] {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
padding: .5rem;
|
||||
border-top: 1px solid #cccccc;
|
||||
cursor: default;
|
||||
}
|
||||
td {
|
||||
padding: .25rem;
|
||||
vertical-align: top;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nameLabel{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.data {
|
||||
white-space: pre;
|
||||
padding-left: .5rem;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding-left: 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
tbody > tr:hover {
|
||||
background-color: #2A2D2E;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
|
||||
</head>
|
||||
<body aria-label="">
|
||||
<table id="process-list"></table>
|
||||
</body>
|
||||
|
||||
<!-- Init Bootstrap Helpers -->
|
||||
<script src="../../../../bootstrap.js"></script>
|
||||
<script src="../../../../vs/loader.js"></script>
|
||||
<script src="../../../../bootstrap-window.js"></script>
|
||||
|
||||
<!-- Startup via processExplorer.js -->
|
||||
<script src="processExplorer.js"></script>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @type {{ load: (modules: string[], resultCallback: (result, configuration: object) => any, options: object) => unknown }}
|
||||
*/
|
||||
const bootstrapWindow = (() => {
|
||||
// @ts-ignore (defined in bootstrap-window.js)
|
||||
return window.MonacoBootstrapWindow;
|
||||
})();
|
||||
|
||||
bootstrapWindow.load(['vs/code/electron-sandbox/processExplorer/processExplorerMain'], function (processExplorer, configuration) {
|
||||
processExplorer.startup(configuration.windowId, configuration.data);
|
||||
}, { forceEnableDeveloperKeybindings: true });
|
||||
@@ -0,0 +1,434 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/processExplorer';
|
||||
import { ElectronService, IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ProcessExplorerStyles, ProcessExplorerData } from 'vs/platform/issue/common/issue';
|
||||
import { applyZoom, zoomIn, zoomOut } from 'vs/platform/windows/electron-sandbox/window';
|
||||
import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu';
|
||||
import { popup } from 'vs/base/parts/contextmenu/electron-sandbox/contextmenu';
|
||||
import { ProcessItem } from 'vs/base/common/processes';
|
||||
import { addDisposableListener, addClass } from 'vs/base/browser/dom';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { MainProcessService } from 'vs/platform/ipc/electron-sandbox/mainProcessService';
|
||||
|
||||
const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/;
|
||||
const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/;
|
||||
|
||||
interface FormattedProcessItem {
|
||||
cpu: number;
|
||||
memory: number;
|
||||
pid: string;
|
||||
name: string;
|
||||
formattedName: string;
|
||||
cmd: string;
|
||||
}
|
||||
|
||||
class ProcessExplorer {
|
||||
private lastRequestTime: number;
|
||||
|
||||
private collapsedStateCache: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
||||
private mapPidToWindowTitle = new Map<number, string>();
|
||||
|
||||
private listeners = new DisposableStore();
|
||||
|
||||
private electronService: IElectronService;
|
||||
|
||||
constructor(windowId: number, private data: ProcessExplorerData) {
|
||||
const mainProcessService = new MainProcessService(windowId);
|
||||
this.electronService = new ElectronService(windowId, mainProcessService) as IElectronService;
|
||||
|
||||
this.applyStyles(data.styles);
|
||||
|
||||
// Map window process pids to titles, annotate process names with this when rendering to distinguish between them
|
||||
ipcRenderer.on('vscode:windowsInfoResponse', (event: unknown, windows: any[]) => {
|
||||
this.mapPidToWindowTitle = new Map<number, string>();
|
||||
windows.forEach(window => this.mapPidToWindowTitle.set(window.pid, window.title));
|
||||
});
|
||||
|
||||
ipcRenderer.on('vscode:listProcessesResponse', (event: unknown, processRoots: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]) => {
|
||||
this.updateProcessInfo(processRoots);
|
||||
this.requestProcessList(0);
|
||||
});
|
||||
|
||||
this.lastRequestTime = Date.now();
|
||||
ipcRenderer.send('vscode:windowsInfoRequest');
|
||||
ipcRenderer.send('vscode:listProcesses');
|
||||
}
|
||||
|
||||
private getProcessList(rootProcess: ProcessItem, isLocal: boolean, totalMem: number): FormattedProcessItem[] {
|
||||
const processes: FormattedProcessItem[] = [];
|
||||
|
||||
if (rootProcess) {
|
||||
this.getProcessItem(processes, rootProcess, 0, isLocal, totalMem);
|
||||
}
|
||||
|
||||
return processes;
|
||||
}
|
||||
|
||||
private getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, indent: number, isLocal: boolean, totalMem: number): void {
|
||||
const isRoot = (indent === 0);
|
||||
|
||||
const MB = 1024 * 1024;
|
||||
|
||||
let name = item.name;
|
||||
if (isRoot) {
|
||||
name = isLocal ? `${this.data.applicationName} main` : 'remote agent';
|
||||
}
|
||||
|
||||
if (name === 'window') {
|
||||
const windowTitle = this.mapPidToWindowTitle.get(item.pid);
|
||||
name = windowTitle !== undefined ? `${name} (${this.mapPidToWindowTitle.get(item.pid)})` : name;
|
||||
}
|
||||
|
||||
// Format name with indent
|
||||
const formattedName = isRoot ? name : `${' '.repeat(indent)} ${name}`;
|
||||
const memory = this.data.platform === 'win32' ? item.mem : (totalMem * (item.mem / 100));
|
||||
processes.push({
|
||||
cpu: item.load,
|
||||
memory: (memory / MB),
|
||||
pid: item.pid.toFixed(0),
|
||||
name,
|
||||
formattedName,
|
||||
cmd: item.cmd
|
||||
});
|
||||
|
||||
// Recurse into children if any
|
||||
if (Array.isArray(item.children)) {
|
||||
item.children.forEach(child => {
|
||||
if (child) {
|
||||
this.getProcessItem(processes, child, indent + 1, isLocal, totalMem);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private attachTo(item: FormattedProcessItem) {
|
||||
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: 'debug.startFromConfig', from: 'processExplorer', args: [config] });
|
||||
}
|
||||
|
||||
private getProcessIdWithHighestProperty(processList: any[], propertyName: string) {
|
||||
let max = 0;
|
||||
let maxProcessId;
|
||||
processList.forEach(process => {
|
||||
if (process[propertyName] > max) {
|
||||
max = process[propertyName];
|
||||
maxProcessId = process.pid;
|
||||
}
|
||||
});
|
||||
|
||||
return maxProcessId;
|
||||
}
|
||||
|
||||
private updateSectionCollapsedState(shouldExpand: boolean, body: HTMLElement, twistie: HTMLImageElement, sectionName: string) {
|
||||
if (shouldExpand) {
|
||||
body.classList.remove('hidden');
|
||||
this.collapsedStateCache.set(sectionName, false);
|
||||
twistie.src = './media/expanded.svg';
|
||||
} else {
|
||||
body.classList.add('hidden');
|
||||
this.collapsedStateCache.set(sectionName, true);
|
||||
twistie.src = './media/collapsed.svg';
|
||||
}
|
||||
}
|
||||
|
||||
private renderProcessFetchError(sectionName: string, errorMessage: string) {
|
||||
const container = document.getElementById('process-list');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const body = document.createElement('tbody');
|
||||
|
||||
this.renderProcessGroupHeader(sectionName, body, container);
|
||||
|
||||
const errorRow = document.createElement('tr');
|
||||
const data = document.createElement('td');
|
||||
data.textContent = errorMessage;
|
||||
data.className = 'error';
|
||||
data.colSpan = 4;
|
||||
errorRow.appendChild(data);
|
||||
|
||||
body.appendChild(errorRow);
|
||||
container.appendChild(body);
|
||||
}
|
||||
|
||||
private renderProcessGroupHeader(sectionName: string, body: HTMLElement, container: HTMLElement) {
|
||||
const headerRow = document.createElement('tr');
|
||||
const data = document.createElement('td');
|
||||
data.textContent = sectionName;
|
||||
data.colSpan = 4;
|
||||
headerRow.appendChild(data);
|
||||
|
||||
const twistie = document.createElement('img');
|
||||
this.updateSectionCollapsedState(!this.collapsedStateCache.get(sectionName), body, twistie, sectionName);
|
||||
data.prepend(twistie);
|
||||
|
||||
this.listeners.add(addDisposableListener(data, 'click', (e) => {
|
||||
const isHidden = body.classList.contains('hidden');
|
||||
this.updateSectionCollapsedState(isHidden, body, twistie, sectionName);
|
||||
}));
|
||||
|
||||
container.appendChild(headerRow);
|
||||
}
|
||||
|
||||
private renderTableSection(sectionName: string, processList: FormattedProcessItem[], renderManySections: boolean, sectionIsLocal: boolean): void {
|
||||
const container = document.getElementById('process-list');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const highestCPUProcess = this.getProcessIdWithHighestProperty(processList, 'cpu');
|
||||
const highestMemoryProcess = this.getProcessIdWithHighestProperty(processList, 'memory');
|
||||
|
||||
const body = document.createElement('tbody');
|
||||
|
||||
if (renderManySections) {
|
||||
this.renderProcessGroupHeader(sectionName, body, container);
|
||||
}
|
||||
|
||||
processList.forEach(p => {
|
||||
const row = document.createElement('tr');
|
||||
row.id = p.pid.toString();
|
||||
|
||||
const cpu = document.createElement('td');
|
||||
p.pid === highestCPUProcess
|
||||
? cpu.classList.add('centered', 'highest')
|
||||
: cpu.classList.add('centered');
|
||||
cpu.textContent = p.cpu.toFixed(0);
|
||||
|
||||
const memory = document.createElement('td');
|
||||
p.pid === highestMemoryProcess
|
||||
? memory.classList.add('centered', 'highest')
|
||||
: memory.classList.add('centered');
|
||||
memory.textContent = p.memory.toFixed(0);
|
||||
|
||||
const pid = document.createElement('td');
|
||||
pid.classList.add('centered');
|
||||
pid.textContent = p.pid;
|
||||
|
||||
const name = document.createElement('th');
|
||||
name.scope = 'row';
|
||||
name.classList.add('data');
|
||||
name.title = p.cmd;
|
||||
name.textContent = p.formattedName;
|
||||
|
||||
row.append(cpu, memory, pid, name);
|
||||
|
||||
this.listeners.add(addDisposableListener(row, 'contextmenu', (e) => {
|
||||
this.showContextMenu(e, p, sectionIsLocal);
|
||||
}));
|
||||
|
||||
body.appendChild(row);
|
||||
});
|
||||
|
||||
container.appendChild(body);
|
||||
}
|
||||
|
||||
private async updateProcessInfo(processLists: [{ name: string, rootProcess: ProcessItem | IRemoteDiagnosticError }]): Promise<void> {
|
||||
const container = document.getElementById('process-list');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '';
|
||||
this.listeners.clear();
|
||||
|
||||
const tableHead = document.createElement('thead');
|
||||
tableHead.innerHTML = `<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>`;
|
||||
|
||||
container.append(tableHead);
|
||||
|
||||
const hasMultipleMachines = Object.keys(processLists).length > 1;
|
||||
const totalMem = await this.electronService.getTotalMem();
|
||||
processLists.forEach((remote, i) => {
|
||||
const isLocal = i === 0;
|
||||
if (isRemoteDiagnosticError(remote.rootProcess)) {
|
||||
this.renderProcessFetchError(remote.name, remote.rootProcess.errorMessage);
|
||||
} else {
|
||||
this.renderTableSection(remote.name, this.getProcessList(remote.rootProcess, isLocal, totalMem), hasMultipleMachines, isLocal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private applyStyles(styles: ProcessExplorerStyles): void {
|
||||
const styleTag = document.createElement('style');
|
||||
const content: string[] = [];
|
||||
|
||||
if (styles.hoverBackground) {
|
||||
content.push(`tbody > tr:hover, table > tr:hover { background-color: ${styles.hoverBackground}; }`);
|
||||
}
|
||||
|
||||
if (styles.hoverForeground) {
|
||||
content.push(`tbody > tr:hover, table > tr:hover { color: ${styles.hoverForeground}; }`);
|
||||
}
|
||||
|
||||
if (styles.highlightForeground) {
|
||||
content.push(`.highest { color: ${styles.highlightForeground}; }`);
|
||||
}
|
||||
|
||||
styleTag.innerHTML = content.join('\n');
|
||||
if (document.head) {
|
||||
document.head.appendChild(styleTag);
|
||||
}
|
||||
if (styles.color) {
|
||||
document.body.style.color = styles.color;
|
||||
}
|
||||
}
|
||||
|
||||
private showContextMenu(e: MouseEvent, item: FormattedProcessItem, isLocal: boolean) {
|
||||
e.preventDefault();
|
||||
|
||||
const items: IContextMenuItem[] = [];
|
||||
const pid = Number(item.pid);
|
||||
|
||||
if (isLocal) {
|
||||
items.push({
|
||||
label: localize('killProcess', "Kill Process"),
|
||||
click: () => {
|
||||
this.electronService.killProcess(pid, 'SIGTERM');
|
||||
}
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: localize('forceKillProcess', "Force Kill Process"),
|
||||
click: () => {
|
||||
this.electronService.killProcess(pid, 'SIGKILL');
|
||||
}
|
||||
});
|
||||
|
||||
items.push({
|
||||
type: 'separator'
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
label: localize('copy', "Copy"),
|
||||
click: () => {
|
||||
const row = document.getElementById(pid.toString());
|
||||
if (row) {
|
||||
this.electronService.writeClipboardText(row.innerText);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: localize('copyAll', "Copy All"),
|
||||
click: () => {
|
||||
const processList = document.getElementById('process-list');
|
||||
if (processList) {
|
||||
this.electronService.writeClipboardText(processList.innerText);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (item && isLocal && this.isDebuggable(item.cmd)) {
|
||||
items.push({
|
||||
type: 'separator'
|
||||
});
|
||||
|
||||
items.push({
|
||||
label: localize('debug', "Debug"),
|
||||
click: () => {
|
||||
this.attachTo(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
popup(items);
|
||||
}
|
||||
|
||||
private requestProcessList(totalWaitTime: number): void {
|
||||
setTimeout(() => {
|
||||
const nextRequestTime = Date.now();
|
||||
const waited = totalWaitTime + nextRequestTime - this.lastRequestTime;
|
||||
this.lastRequestTime = nextRequestTime;
|
||||
|
||||
// Wait at least a second between requests.
|
||||
if (waited > 1000) {
|
||||
ipcRenderer.send('vscode:windowsInfoRequest');
|
||||
ipcRenderer.send('vscode:listProcesses');
|
||||
} else {
|
||||
this.requestProcessList(waited);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.listeners.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function startup(windowId: number, data: ProcessExplorerData): void {
|
||||
const platformClass = data.platform === 'win32' ? 'windows' : data.platform === 'linux' ? 'linux' : 'mac';
|
||||
addClass(document.body, platformClass); // used by our fonts
|
||||
applyZoom(data.zoomLevel);
|
||||
|
||||
const processExplorer = new ProcessExplorer(windowId, data);
|
||||
|
||||
document.onkeydown = (e: KeyboardEvent) => {
|
||||
const cmdOrCtrlKey = data.platform === 'darwin' ? e.metaKey : e.ctrlKey;
|
||||
|
||||
// Cmd/Ctrl + zooms in
|
||||
if (cmdOrCtrlKey && e.keyCode === 187) {
|
||||
zoomIn();
|
||||
}
|
||||
|
||||
// Cmd/Ctrl - zooms out
|
||||
if (cmdOrCtrlKey && e.keyCode === 189) {
|
||||
zoomOut();
|
||||
}
|
||||
};
|
||||
|
||||
// Cmd/Ctrl + w closes process explorer
|
||||
window.addEventListener('keydown', e => {
|
||||
const cmdOrCtrlKey = data.platform === 'darwin' ? e.metaKey : e.ctrlKey;
|
||||
if (cmdOrCtrlKey && e.keyCode === 87) {
|
||||
processExplorer.dispose();
|
||||
ipcRenderer.send('vscode:closeProcessExplorer');
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user