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,182 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const path = require('path');
const fs = require('fs');
const remote = require('electron').remote;
const bootstrapWindow = require('../../../../bootstrap-window');
function assign(destination, source) {
return Object.keys(source)
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
}
function parseURLQueryArgs() {
const search = window.location.search || '';
return search.split(/[?&]/)
.filter(function (param) { return !!param; })
.map(function (param) { return param.split('='); })
.filter(function (param) { return param.length === 2; })
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
}
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
function readFile(file) {
return new Promise(function(resolve, reject) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) {
reject(err);
return;
}
resolve(data);
});
});
}
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
function main() {
const args = parseURLQueryArgs();
const configuration = JSON.parse(args['config'] || '{}') || {};
assign(process.env, configuration.userEnv);
//#region Add support for using node_modules.asar
(function () {
const path = require('path');
const Module = require('module');
let NODE_MODULES_PATH = path.join(configuration.appRoot, 'node_modules');
if (/[a-z]\:/.test(NODE_MODULES_PATH)) {
// Make drive letter uppercase
NODE_MODULES_PATH = NODE_MODULES_PATH.charAt(0).toUpperCase() + NODE_MODULES_PATH.substr(1);
}
const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
const originalResolveLookupPaths = Module._resolveLookupPaths;
Module._resolveLookupPaths = function (request, parent, newReturn) {
const result = originalResolveLookupPaths(request, parent, newReturn);
const paths = newReturn ? result : result[1];
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === NODE_MODULES_PATH) {
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
break;
}
}
return result;
};
})();
//#endregion
const extractKey = function (e) {
return [
e.ctrlKey ? 'ctrl-' : '',
e.metaKey ? 'meta-' : '',
e.altKey ? 'alt-' : '',
e.shiftKey ? 'shift-' : '',
e.keyCode
].join('');
};
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
window.addEventListener('keydown', function (e) {
const key = extractKey(e);
if (key === TOGGLE_DEV_TOOLS_KB) {
remote.getCurrentWebContents().toggleDevTools();
} else if (key === RELOAD_KB) {
remote.getCurrentWindow().reload();
}
});
// Load the loader and start loading the workbench
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
// Get the nls configuration into the process.env as early as possible.
var nlsConfig = { availableLanguages: {} };
const config = process.env['VSCODE_NLS_CONFIG'];
if (config) {
process.env['VSCODE_NLS_CONFIG'] = config;
try {
nlsConfig = JSON.parse(config);
} catch (e) { /*noop*/ }
}
if (nlsConfig._resolvedLanguagePackCoreLocation) {
let bundles = Object.create(null);
nlsConfig.loadBundle = function(bundle, language, cb) {
let result = bundles[bundle];
if (result) {
cb(undefined, result);
return;
}
let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json');
readFile(bundleFile).then(function (content) {
let json = JSON.parse(content);
bundles[bundle] = json;
cb(undefined, json);
}).catch((error) => {
try {
if (nlsConfig._corruptedFile) {
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
}
} finally {
cb(error, undefined);
}
});
};
}
var locale = nlsConfig.availableLanguages['*'] || 'en';
if (locale === 'zh-tw') {
locale = 'zh-Hant';
} else if (locale === 'zh-cn') {
locale = 'zh-Hans';
}
window.document.documentElement.setAttribute('lang', locale);
// Load the loader
const loaderFilename = configuration.appRoot + '/out/vs/loader.js';
const loaderSource = fs.readFileSync(loaderFilename);
require('vm').runInThisContext(loaderSource, { filename: loaderFilename });
var define = global.define;
global.define = undefined;
window.nodeRequire = require.__$__nodeRequire;
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
window.MonacoEnvironment = {};
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
nodeCachedDataDir: configuration.nodeCachedDataDir,
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
});
if (nlsConfig.pseudo) {
require(['vs/nls'], function (nlsPlugin) {
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
});
}
require(['vs/code/electron-browser/issue/issueReporterMain'], (issueReporter) => {
issueReporter.startup(configuration);
});
}
main();
bootstrapWindow.load(['vs/code/electron-browser/issue/issueReporterMain'], function (issueReporter, configuration) {
issueReporter.startup(configuration);
}, { forceEnableDeveloperKeybindings: true });

View File

@@ -3,10 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/issueReporter';
import { shell, ipcRenderer, webFrame, remote, clipboard } from 'electron';
import { shell, ipcRenderer, webFrame, clipboard } from 'electron';
import { localize } from 'vs/nls';
import { $ } from 'vs/base/browser/dom';
import * as collections from 'vs/base/common/collections';
@@ -19,25 +17,24 @@ import { debounce } from 'vs/base/common/decorators';
import * as platform from 'vs/base/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser';
import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc';
import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows';
import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures } from 'vs/platform/issue/common/issue';
import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage';
import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc';
import { ILogService, getLogLevel } from 'vs/platform/log/common/log';
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';
@@ -72,6 +69,7 @@ export class IssueReporter extends Disposable {
private receivedSystemInfo = false;
private receivedPerformanceInfo = false;
private shouldQueueSearch = false;
private hasBeenSubmitted = false;
private previewButton: Button;
@@ -91,7 +89,7 @@ export class IssueReporter extends Disposable {
this.previewButton = new Button(document.getElementById('issue-reporter'));
ipcRenderer.on('issuePerformanceInfoResponse', (event, info) => {
ipcRenderer.on('vscode:issuePerformanceInfoResponse', (event, info) => {
this.logService.trace('issueReporter: Received performance data');
this.issueReporterModel.update(info);
this.receivedPerformanceInfo = true;
@@ -102,7 +100,7 @@ export class IssueReporter extends Disposable {
this.updatePreviewButtonState();
});
ipcRenderer.on('issueSystemInfoResponse', (event, info) => {
ipcRenderer.on('vscode:issueSystemInfoResponse', (event, info) => {
this.logService.trace('issueReporter: Received system data');
this.issueReporterModel.update({ systemInfo: info });
this.receivedSystemInfo = true;
@@ -111,9 +109,9 @@ export class IssueReporter extends Disposable {
this.updatePreviewButtonState();
});
ipcRenderer.send('issueSystemInfoRequest');
ipcRenderer.send('vscode:issueSystemInfoRequest');
if (configuration.data.issueType === IssueType.PerformanceIssue) {
ipcRenderer.send('issuePerformanceInfoRequest');
ipcRenderer.send('vscode:issuePerformanceInfoRequest');
}
this.logService.trace('issueReporter: Sent data requests');
@@ -213,11 +211,9 @@ export class IssueReporter extends Disposable {
document.body.style.color = styles.color;
}
private handleExtensionData(extensions: ILocalExtension[]) {
private handleExtensionData(extensions: IssueReporterExtensionData[]) {
const { nonThemes, themes } = collections.groupBy(extensions, ext => {
const manifestKeys = ext.manifest.contributes ? Object.keys(ext.manifest.contributes) : [];
const onlyTheme = !ext.manifest.activationEvents && manifestKeys.length === 1 && manifestKeys[0] === 'themes';
return onlyTheme ? 'themes' : 'nonThemes';
return ext.isTheme ? 'themes' : 'nonThemes';
});
const numberOfThemeExtesions = themes && themes.length;
@@ -288,7 +284,7 @@ export class IssueReporter extends Disposable {
const instantiationService = new InstantiationService(serviceCollection, true);
if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) {
const channel = getDelayedChannel<ITelemetryAppenderChannel>(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender')));
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService));
const commonProperties = resolveCommonProperties(product.commit, pkg.version, configuration.machineId, this.environmentService.installSourcePath);
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
@@ -308,7 +304,7 @@ export class IssueReporter extends Disposable {
const issueType = parseInt((<HTMLInputElement>event.target).value);
this.issueReporterModel.update({ issueType: issueType });
if (issueType === IssueType.PerformanceIssue && !this.receivedPerformanceInfo) {
ipcRenderer.send('issuePerformanceInfoRequest');
ipcRenderer.send('vscode:issuePerformanceInfoRequest');
}
this.updatePreviewButtonState();
this.render();
@@ -383,15 +379,19 @@ export class IssueReporter extends Disposable {
this.previewButton.onDidClick(() => this.createIssue());
function sendWorkbenchCommand(commandId: string) {
ipcRenderer.send('vscode:workbenchCommand', { id: commandId, from: 'issueReporter' });
}
this.addEventListener('disableExtensions', 'click', () => {
ipcRenderer.send('workbenchCommand', 'workbench.action.reloadWindowWithExtensionsDisabled');
sendWorkbenchCommand('workbench.action.reloadWindowWithExtensionsDisabled');
});
this.addEventListener('disableExtensions', 'keydown', (e: KeyboardEvent) => {
e.stopPropagation();
if (e.keyCode === 13 || e.keyCode === 32) {
ipcRenderer.send('workbenchCommand', 'workbench.extensions.action.disableAll');
ipcRenderer.send('workbenchCommand', 'workbench.action.reloadWindow');
sendWorkbenchCommand('workbench.extensions.action.disableAll');
sendWorkbenchCommand('workbench.action.reloadWindow');
}
});
@@ -400,7 +400,21 @@ export class IssueReporter extends Disposable {
// Cmd/Ctrl+Enter previews issue and closes window
if (cmdOrCtrlKey && e.keyCode === 13) {
if (this.createIssue()) {
remote.getCurrentWindow().close();
ipcRenderer.send('vscode:closeIssueReporter');
}
}
// Cmd/Ctrl + w closes issue window
if (cmdOrCtrlKey && e.keyCode === 87) {
e.stopPropagation();
e.preventDefault();
const issueTitle = (<HTMLInputElement>document.getElementById('issue-title'))!.value;
const { issueDescription } = this.issueReporterModel.getData();
if (!this.hasBeenSubmitted && (issueTitle || issueDescription)) {
ipcRenderer.send('vscode:issueReporterConfirmClose');
} else {
ipcRenderer.send('vscode:closeIssueReporter');
}
}
@@ -459,12 +473,12 @@ export class IssueReporter extends Disposable {
private getExtensionRepositoryUrl(): string {
const selectedExtension = this.issueReporterModel.getData().selectedExtension;
return selectedExtension && selectedExtension.manifest && selectedExtension.manifest.repository && selectedExtension.manifest.repository.url;
return selectedExtension && selectedExtension.repositoryUrl;
}
private getExtensionBugsUrl(): string {
const selectedExtension = this.issueReporterModel.getData().selectedExtension;
return selectedExtension && selectedExtension.manifest && selectedExtension.manifest.bugs && selectedExtension.manifest.bugs.url;
return selectedExtension && selectedExtension.bugsUrl;
}
private searchVSCodeIssues(title: string, issueDescription: string): void {
@@ -775,6 +789,7 @@ export class IssueReporter extends Disposable {
}
*/
this.telemetryService.publicLog('issueReporterSubmit', { issueType: this.issueReporterModel.getData().issueType, numSimilarIssuesDisplayed: this.numberOfSearchResultsDisplayed });
this.hasBeenSubmitted = true;
const baseUrl = this.getIssueUrlWithTitle((<HTMLInputElement>document.getElementById('issue-title')).value);
const issueBody = this.issueReporterModel.serialize();
@@ -785,7 +800,7 @@ export class IssueReporter extends Disposable {
url = baseUrl + `&body=${encodeURIComponent(localize('pasteData', "We have written the needed data into your clipboard because it was too large to send. Please paste."))}`;
}
shell.openExternal(url);
ipcRenderer.send('vscode:openExternal', url);
return true;
}
@@ -834,7 +849,7 @@ export class IssueReporter extends Disposable {
target.innerHTML = `<table>${tableHtml}</table>`;
}
private updateExtensionSelector(extensions: ILocalExtension[]): void {
private updateExtensionSelector(extensions: IssueReporterExtensionData[]): void {
interface IOption {
name: string;
id: string;
@@ -842,8 +857,8 @@ export class IssueReporter extends Disposable {
const extensionOptions: IOption[] = extensions.map(extension => {
return {
name: extension.manifest.displayName || extension.manifest.name || '',
id: extension.identifier.id
name: extension.displayName || extension.name || '',
id: extension.id
};
});
@@ -869,7 +884,7 @@ export class IssueReporter extends Disposable {
this.addEventListener('extension-selector', 'change', (e: Event) => {
const selectedExtensionId = (<HTMLInputElement>e.target).value;
const extensions = this.issueReporterModel.getData().allExtensions;
const matches = extensions.filter(extension => extension.identifier.id === selectedExtensionId);
const matches = extensions.filter(extension => extension.id === selectedExtensionId);
if (matches.length) {
this.issueReporterModel.update({ selectedExtension: matches[0] });
@@ -891,7 +906,7 @@ export class IssueReporter extends Disposable {
document.querySelector('.block-workspace .block-info code').textContent = '\n' + state.workspaceInfo;
}
private updateExtensionTable(extensions: ILocalExtension[], numThemeExtensions: number): void {
private updateExtensionTable(extensions: IssueReporterExtensionData[], numThemeExtensions: number): void {
const target = document.querySelector('.block-extensions .block-info');
if (this.environmentService.disableExtensions) {
@@ -911,7 +926,7 @@ export class IssueReporter extends Disposable {
target.innerHTML = `<table>${table}</table>${themeExclusionStr}`;
}
private updateSearchedExtensionTable(extensions: ILocalExtension[]): void {
private updateSearchedExtensionTable(extensions: IssueReporterExtensionData[]): void {
const target = document.querySelector('.block-searchedExtensions .block-info');
if (!extensions.length) {
@@ -923,7 +938,7 @@ export class IssueReporter extends Disposable {
target.innerHTML = `<table>${table}</table>`;
}
private getExtensionTableHtml(extensions: ILocalExtension[]): string {
private getExtensionTableHtml(extensions: IssueReporterExtensionData[]): string {
let table = `
<tr>
<th>Extension</th>
@@ -934,9 +949,9 @@ export class IssueReporter extends Disposable {
table += extensions.map(extension => {
return `
<tr>
<td>${extension.manifest.name}</td>
<td>${extension.manifest.publisher.substr(0, 3)}</td>
<td>${extension.manifest.version}</td>
<td>${extension.name}</td>
<td>${extension.publisher.substr(0, 3)}</td>
<td>${extension.version}</td>
</tr>`;
}).join('');

View File

@@ -3,11 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { assign } from 'vs/base/common/objects';
import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IssueType, ISettingSearchResult } from 'vs/platform/issue/common/issue';
import { IssueType, ISettingSearchResult, IssueReporterExtensionData } from 'vs/platform/issue/common/issue';
export interface IssueReporterData {
issueType?: IssueType;
@@ -26,11 +23,11 @@ export interface IssueReporterData {
includeSettingsSearchDetails?: boolean;
numberOfThemeExtesions?: number;
allExtensions?: ILocalExtension[];
enabledNonThemeExtesions?: ILocalExtension[];
allExtensions?: IssueReporterExtensionData[];
enabledNonThemeExtesions?: IssueReporterExtensionData[];
extensionsDisabled?: boolean;
fileOnExtension?: boolean;
selectedExtension?: ILocalExtension;
selectedExtension?: IssueReporterExtensionData;
actualSearchResults?: ISettingSearchResult[];
query?: string;
filterResultCount?: number;
@@ -79,12 +76,12 @@ ${this.getInfos()}
|| this._data.issueType === IssueType.PerformanceIssue
|| this._data.issueType === IssueType.FeatureRequest;
return fileOnExtensionSupported && this._data.fileOnExtension;
return !!(fileOnExtensionSupported && this._data.fileOnExtension);
}
private getExtensionVersion(): string {
if (this.fileOnExtension()) {
return `\nExtension version: ${this._data.selectedExtension.manifest.version}`;
if (this.fileOnExtension() && this._data.selectedExtension) {
return `\nExtension version: ${this._data.selectedExtension.version}`;
} else {
return '';
}
@@ -201,7 +198,7 @@ ${this._data.workspaceInfo};
let tableHeader = `Extension|Author (truncated)|Version
---|---|---`;
const table = this._data.enabledNonThemeExtesions.map(e => {
return `${e.manifest.name}|${e.manifest.publisher.substr(0, 3)}|${e.manifest.version}`;
return `${e.name}|${e.publisher.substr(0, 3)}|${e.version}`;
}).join('\n');
return `<details><summary>Extensions (${this._data.enabledNonThemeExtesions.length})</summary>

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { escape } from 'vs/base/common/strings';
import { localize } from 'vs/nls';

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { endsWith, rtrim } from 'vs/base/common/strings';
export function normalizeGitHubUrl(url: string): string {

View File

@@ -24,6 +24,10 @@ td {
vertical-align: top;
}
label {
user-select: none;
}
.block-settingsSearchResults-details {
padding-bottom: .5rem;
}

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel';
import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil';

View File

@@ -8,7 +8,7 @@
</head>
<body aria-label="">
<div id="process-list"></div>
<table id="process-list" aria-live="polite"></table>
</body>
<!-- Startup via processExplorer.js -->

View File

@@ -3,182 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const path = require('path');
const fs = require('fs');
const remote = require('electron').remote;
const bootstrapWindow = require('../../../../bootstrap-window');
function assign(destination, source) {
return Object.keys(source)
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
}
function parseURLQueryArgs() {
const search = window.location.search || '';
return search.split(/[?&]/)
.filter(function (param) { return !!param; })
.map(function (param) { return param.split('='); })
.filter(function (param) { return param.length === 2; })
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
}
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
function readFile(file) {
return new Promise(function(resolve, reject) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) {
reject(err);
return;
}
resolve(data);
});
});
}
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
function main() {
const args = parseURLQueryArgs();
const configuration = JSON.parse(args['config'] || '{}') || {};
assign(process.env, configuration.userEnv);
//#region Add support for using node_modules.asar
(function () {
const path = require('path');
const Module = require('module');
let NODE_MODULES_PATH = path.join(configuration.appRoot, 'node_modules');
if (/[a-z]\:/.test(NODE_MODULES_PATH)) {
// Make drive letter uppercase
NODE_MODULES_PATH = NODE_MODULES_PATH.charAt(0).toUpperCase() + NODE_MODULES_PATH.substr(1);
}
const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
const originalResolveLookupPaths = Module._resolveLookupPaths;
Module._resolveLookupPaths = function (request, parent, newReturn) {
const result = originalResolveLookupPaths(request, parent, newReturn);
const paths = newReturn ? result : result[1];
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === NODE_MODULES_PATH) {
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
break;
}
}
return result;
};
})();
//#endregion
// Get the nls configuration into the process.env as early as possible.
var nlsConfig = { availableLanguages: {} };
const config = process.env['VSCODE_NLS_CONFIG'];
if (config) {
process.env['VSCODE_NLS_CONFIG'] = config;
try {
nlsConfig = JSON.parse(config);
} catch (e) { /*noop*/ }
}
if (nlsConfig._resolvedLanguagePackCoreLocation) {
let bundles = Object.create(null);
nlsConfig.loadBundle = function(bundle, language, cb) {
let result = bundles[bundle];
if (result) {
cb(undefined, result);
return;
}
let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json');
readFile(bundleFile).then(function (content) {
let json = JSON.parse(content);
bundles[bundle] = json;
cb(undefined, json);
}).catch((error) => {
try {
if (nlsConfig._corruptedFile) {
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
}
} finally {
cb(error, undefined);
}
});
};
}
var locale = nlsConfig.availableLanguages['*'] || 'en';
if (locale === 'zh-tw') {
locale = 'zh-Hant';
} else if (locale === 'zh-cn') {
locale = 'zh-Hans';
}
window.document.documentElement.setAttribute('lang', locale);
const extractKey = function (e) {
return [
e.ctrlKey ? 'ctrl-' : '',
e.metaKey ? 'meta-' : '',
e.altKey ? 'alt-' : '',
e.shiftKey ? 'shift-' : '',
e.keyCode
].join('');
};
const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I
const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R
window.addEventListener('keydown', function (e) {
const key = extractKey(e);
if (key === TOGGLE_DEV_TOOLS_KB) {
remote.getCurrentWebContents().toggleDevTools();
} else if (key === RELOAD_KB) {
remote.getCurrentWindow().reload();
}
});
// Load the loader
const loaderFilename = configuration.appRoot + '/out/vs/loader.js';
const loaderSource = fs.readFileSync(loaderFilename);
require('vm').runInThisContext(loaderSource, { filename: loaderFilename });
var define = global.define;
global.define = undefined;
window.nodeRequire = require.__$__nodeRequire;
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
window.MonacoEnvironment = {};
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
nodeCachedDataDir: configuration.nodeCachedDataDir,
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
});
if (nlsConfig.pseudo) {
require(['vs/nls'], function (nlsPlugin) {
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
});
}
require([
'vs/code/electron-browser/processExplorer/processExplorerMain'
], function (processExplorer) {
processExplorer.startup(configuration.data);
});
}
main();
bootstrapWindow.load(['vs/code/electron-browser/processExplorer/processExplorerMain'], function (processExplorer, configuration) {
processExplorer.startup(configuration.data);
}, { forceEnableDeveloperKeybindings: true });

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);

View File

@@ -79,11 +79,6 @@
</body>
<script>
const electron = require('electron');
const shell = electron.shell;
const ipc = electron.ipcRenderer;
const remote = electron.remote;
const currentWindow = remote.getCurrentWindow();
function promptForCredentials(data) {
return new Promise((c, e) => {

View File

@@ -2,16 +2,17 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner';
export function createSharedProcessContributions(service: IInstantiationService): IDisposable {
return combinedDisposable([
service.createInstance(NodeCachedDataCleaner),
service.createInstance(LanguagePackCachedDataCleaner)
service.createInstance(LanguagePackCachedDataCleaner),
service.createInstance(StorageDataCleaner)
]);
}

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as path from 'path';
import * as pfs from 'vs/base/node/pfs';
@@ -51,7 +50,7 @@ export class LanguagePackCachedDataCleaner {
}
private _manageCachedDataSoon(): void {
let handle = setTimeout(async () => {
let handle: any = setTimeout(async () => {
handle = undefined;
this._logService.info('Starting to clean up unused language packs.');
const maxAge = product.nameLong.indexOf('Insiders') >= 0

View File

@@ -2,12 +2,10 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { basename, dirname, join } from 'path';
import { onUnexpectedError } from 'vs/base/common/errors';
import { TPromise } from 'vs/base/common/winjs.base';
import { join, basename, dirname } from 'path';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { readdir, rimraf, stat } from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import product from 'vs/platform/node/product';
@@ -43,13 +41,13 @@ export class NodeCachedDataCleaner {
const nodeCachedDataRootDir = dirname(this._environmentService.nodeCachedDataDir);
const nodeCachedDataCurrent = basename(this._environmentService.nodeCachedDataDir);
let handle = setTimeout(() => {
let handle: any = setTimeout(() => {
handle = undefined;
readdir(nodeCachedDataRootDir).then(entries => {
const now = Date.now();
const deletes: TPromise<any>[] = [];
const deletes: Thenable<any>[] = [];
entries.forEach(entry => {
// name check
@@ -72,9 +70,9 @@ export class NodeCachedDataCleaner {
}
});
return TPromise.join(deletes);
return Promise.all(deletes);
}).done(undefined, onUnexpectedError);
}).then(undefined, onUnexpectedError);
}, 30 * 1000);

View File

@@ -0,0 +1,57 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { join } from 'path';
import { readdir, readFile, rimraf } from 'vs/base/node/pfs';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup';
export class StorageDataCleaner extends Disposable {
// Workspace/Folder storage names are MD5 hashes (128bits / 4 due to hex presentation)
private static NON_EMPTY_WORKSPACE_ID_LENGTH = 128 / 4;
constructor(
@IEnvironmentService private environmentService: IEnvironmentService
) {
super();
this.cleanUpStorageSoon();
}
private cleanUpStorageSoon(): void {
let handle: any = setTimeout(() => {
handle = void 0;
// Leverage the backup workspace file to find out which empty workspace is currently in use to
// determine which empty workspace storage can safely be deleted
readFile(this.environmentService.backupWorkspacesPath, 'utf8').then(contents => {
const workspaces = JSON.parse(contents) as IBackupWorkspacesFormat;
const emptyWorkspaces = workspaces.emptyWorkspaceInfos.map(info => info.backupFolder);
// Read all workspace storage folders that exist
return readdir(this.environmentService.workspaceStorageHome).then(storageFolders => {
const deletes: Promise<void>[] = [];
storageFolders.forEach(storageFolder => {
if (storageFolder.length === StorageDataCleaner.NON_EMPTY_WORKSPACE_ID_LENGTH) {
return;
}
if (emptyWorkspaces.indexOf(storageFolder) === -1) {
deletes.push(rimraf(join(this.environmentService.workspaceStorageHome, storageFolder)));
}
});
return Promise.all(deletes);
});
}).then(null, onUnexpectedError);
}, 30 * 1000);
this._register(toDisposable(() => clearTimeout(handle)));
}
}

View File

@@ -3,168 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
'use strict';
const path = require('path');
const fs = require('fs');
const bootstrap = require('../../../../bootstrap');
const bootstrapWindow = require('../../../../bootstrap-window');
function assign(destination, source) {
return Object.keys(source)
.reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
}
// Avoid Monkey Patches from Application Insights
bootstrap.avoidMonkeyPatchFromAppInsights();
function parseURLQueryArgs() {
const search = window.location.search || '';
return search.split(/[?&]/)
.filter(function (param) { return !!param; })
.map(function (param) { return param.split('='); })
.filter(function (param) { return param.length === 2; })
.reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
}
function createScript(src, onload) {
const script = document.createElement('script');
script.src = src;
script.addEventListener('load', onload);
const head = document.getElementsByTagName('head')[0];
head.insertBefore(script, head.lastChild);
}
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
function readFile(file) {
return new Promise(function(resolve, reject) {
fs.readFile(file, 'utf8', function(err, data) {
if (err) {
reject(err);
return;
}
resolve(data);
});
bootstrapWindow.load(['vs/code/electron-browser/sharedProcess/sharedProcessMain'], function (sharedProcess, configuration) {
sharedProcess.startup({
machineId: configuration.machineId
});
}
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
function main() {
const args = parseURLQueryArgs();
const configuration = JSON.parse(args['config'] || '{}') || {};
//#region Add support for using node_modules.asar
(function () {
const path = require('path');
const Module = require('module');
let NODE_MODULES_PATH = path.join(configuration.appRoot, 'node_modules');
if (/[a-z]\:/.test(NODE_MODULES_PATH)) {
// Make drive letter uppercase
NODE_MODULES_PATH = NODE_MODULES_PATH.charAt(0).toUpperCase() + NODE_MODULES_PATH.substr(1);
}
const NODE_MODULES_ASAR_PATH = NODE_MODULES_PATH + '.asar';
const originalResolveLookupPaths = Module._resolveLookupPaths;
Module._resolveLookupPaths = function (request, parent, newReturn) {
const result = originalResolveLookupPaths(request, parent, newReturn);
const paths = newReturn ? result : result[1];
for (let i = 0, len = paths.length; i < len; i++) {
if (paths[i] === NODE_MODULES_PATH) {
paths.splice(i, 0, NODE_MODULES_ASAR_PATH);
break;
}
}
return result;
};
})();
//#endregion
// Correctly inherit the parent's environment
assign(process.env, configuration.userEnv);
// Get the nls configuration into the process.env as early as possible.
var nlsConfig = { availableLanguages: {} };
const config = process.env['VSCODE_NLS_CONFIG'];
if (config) {
process.env['VSCODE_NLS_CONFIG'] = config;
try {
nlsConfig = JSON.parse(config);
} catch (e) { /*noop*/ }
}
if (nlsConfig._resolvedLanguagePackCoreLocation) {
let bundles = Object.create(null);
nlsConfig.loadBundle = function(bundle, language, cb) {
let result = bundles[bundle];
if (result) {
cb(undefined, result);
return;
}
let bundleFile = path.join(nlsConfig._resolvedLanguagePackCoreLocation, bundle.replace(/\//g, '!') + '.nls.json');
readFile(bundleFile).then(function (content) {
let json = JSON.parse(content);
bundles[bundle] = json;
cb(undefined, json);
}).catch((error) => {
try {
if (nlsConfig._corruptedFile) {
writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); });
}
} finally {
cb(error, undefined);
}
});
};
}
var locale = nlsConfig.availableLanguages['*'] || 'en';
if (locale === 'zh-tw') {
locale = 'zh-Hant';
} else if (locale === 'zh-cn') {
locale = 'zh-Hans';
}
window.document.documentElement.setAttribute('lang', locale);
// Load the loader and start loading the workbench
const rootUrl = uriFromPath(configuration.appRoot) + '/out';
// In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
// loads as soon as the loader loads. To be able to have pseudo translation
createScript(rootUrl + '/vs/loader.js', function () {
var define = global.define;
global.define = undefined;
define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
window.MonacoEnvironment = {};
require.config({
baseUrl: rootUrl,
'vs/nls': nlsConfig,
nodeCachedDataDir: configuration.nodeCachedDataDir,
nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
});
if (nlsConfig.pseudo) {
require(['vs/nls'], function (nlsPlugin) {
nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
});
}
require(['vs/code/electron-browser/sharedProcess/sharedProcessMain'], function (sharedProcess) {
sharedProcess.startup({
machineId: configuration.machineId
});
});
});
}
main();
});

View File

@@ -3,20 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as fs from 'fs';
import * as platform from 'vs/base/common/platform';
import product from 'vs/platform/node/product';
import pkg from 'vs/platform/node/package';
import { serve, Server, connect } from 'vs/base/parts/ipc/node/ipc.net';
import { TPromise } from 'vs/base/common/winjs.base';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
@@ -27,22 +24,26 @@ import { RequestService } from 'vs/platform/request/electron-browser/requestServ
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc';
import { ipcRenderer } from 'electron';
import { createSharedProcessContributions } from 'vs/code/electron-browser/sharedProcess/contrib/contributions';
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc';
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { LocalizationsChannel } from 'vs/platform/localizations/common/localizationsIpc';
import { DialogChannelClient } from 'vs/platform/dialogs/common/dialogIpc';
import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc';
import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { DownloadService } from 'vs/platform/download/node/downloadService';
import { IDownloadService } from 'vs/platform/download/common/download';
import { StaticRouter } from 'vs/base/parts/ipc/node/ipc';
import { DefaultURITransformer } from 'vs/base/common/uriIpc';
export interface ISharedProcessConfiguration {
readonly machineId: string;
@@ -62,12 +63,19 @@ const eventPrefix = 'monacoworkbench';
function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void {
const services = new ServiceCollection();
const disposables: IDisposable[] = [];
process.once('exit', () => dispose(disposables));
const onExit = () => dispose(disposables);
process.once('exit', onExit);
ipcRenderer.once('handshake:goodbye', onExit);
disposables.push(server);
const environmentService = new EnvironmentService(initData.args, process.execPath);
const mainRoute = () => TPromise.as('main');
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: mainRoute, routeEvent: mainRoute }));
const mainRouter = new StaticRouter(ctx => ctx === 'main');
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', mainRouter));
const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath));
disposables.push(logService);
@@ -77,14 +85,15 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
services.set(ILogService, logService);
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IDownloadService, new SyncDescriptor(DownloadService));
const windowsChannel = server.getChannel('windows', { routeCall: mainRoute, routeEvent: mainRoute });
const windowsChannel = server.getChannel('windows', mainRouter);
const windowsService = new WindowsChannelClient(windowsChannel);
services.set(IWindowsService, windowsService);
const activeWindowManager = new ActiveWindowManager(windowsService);
const route = () => activeWindowManager.getActiveClientId();
const dialogChannel = server.getChannel('dialog', { routeCall: route, routeEvent: route });
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
const dialogChannel = server.getChannel('dialog', activeWindowRouter);
services.set(IDialogService, new DialogChannelClient(dialogChannel));
const instantiationService = new InstantiationService(services);
@@ -92,27 +101,28 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
instantiationService.invokeFunction(accessor => {
const services = new ServiceCollection();
const environmentService = accessor.get(IEnvironmentService);
const { appRoot, extensionsPath, extensionDevelopmentPath, isBuilt, installSourcePath } = environmentService;
const { appRoot, extensionsPath, extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService;
const telemetryLogService = new FollowerLogService(logLevelClient, createSpdLogService('telemetry', initData.logLevel, environmentService.logsPath));
telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.');
telemetryLogService.info('===========================================================');
let appInsightsAppender: ITelemetryAppender = NullAppender;
if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService);
disposables.push(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data
}
server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender));
if (!extensionDevelopmentPath && !environmentService.args['disable-telemetry'] && product.enableTelemetry) {
let appInsightsAppender: ITelemetryAppender | null = NullAppender;
if (!extensionDevelopmentLocationURI && !environmentService.args['disable-telemetry'] && product.enableTelemetry) {
if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService);
disposables.push(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data
}
const config: ITelemetryServiceConfig = {
appender: combinedAppender(appInsightsAppender, new LogAppender(logService)),
commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath),
piiPaths: [appRoot, extensionsPath]
};
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, config));
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
} else {
services.set(ITelemetryService, NullTelemetryService);
}
server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender));
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
@@ -121,8 +131,9 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
const instantiationService2 = instantiationService.createChild(services);
instantiationService2.invokeFunction(accessor => {
const extensionManagementService = accessor.get(IExtensionManagementService);
const channel = new ExtensionManagementChannel(extensionManagementService);
const channel = new ExtensionManagementChannel(extensionManagementService, () => DefaultURITransformer);
server.registerChannel('extensions', channel);
// clean up deprecated extensions
@@ -138,11 +149,11 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
});
}
function setupIPC(hook: string): TPromise<Server> {
function setup(retry: boolean): TPromise<Server> {
function setupIPC(hook: string): Thenable<Server> {
function setup(retry: boolean): Thenable<Server> {
return serve(hook).then(null, err => {
if (!retry || platform.isWindows || err.code !== 'EADDRINUSE') {
return TPromise.wrapError(err);
return Promise.reject(err);
}
// should retry, not windows and eaddrinuse
@@ -151,7 +162,7 @@ function setupIPC(hook: string): TPromise<Server> {
client => {
// we could connect to a running instance. this is not good, abort
client.dispose();
return TPromise.wrapError(new Error('There is an instance already running.'));
return Promise.reject(new Error('There is an instance already running.'));
},
err => {
// it happens on Linux and OS X that the pipe is left behind
@@ -160,7 +171,7 @@ function setupIPC(hook: string): TPromise<Server> {
try {
fs.unlinkSync(hook);
} catch (e) {
return TPromise.wrapError(new Error('Error deleting the shared ipc hook.'));
return Promise.reject(new Error('Error deleting the shared ipc hook.'));
}
return setup(false);
@@ -172,15 +183,14 @@ function setupIPC(hook: string): TPromise<Server> {
return setup(true);
}
function startHandshake(): TPromise<ISharedProcessInitData> {
return new TPromise<ISharedProcessInitData>((c, e) => {
async function handshake(configuration: ISharedProcessConfiguration): Promise<void> {
const data = await new Promise<ISharedProcessInitData>(c => {
ipcRenderer.once('handshake:hey there', (_: any, r: ISharedProcessInitData) => c(r));
ipcRenderer.send('handshake:hello');
});
}
function handshake(configuration: ISharedProcessConfiguration): TPromise<void> {
return startHandshake()
.then(data => setupIPC(data.sharedIPCHandle).then(server => main(server, data, configuration)))
.then(() => ipcRenderer.send('handshake:im ready'));
}
const server = await setupIPC(data.sharedIPCHandle);
main(server, data, configuration);
ipcRenderer.send('handshake:im ready');
}

View File

@@ -0,0 +1,19 @@
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- // {{SQL CARBON EDIT}}
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: vscode-remote:; 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 class="monaco-shell vs-dark" aria-label="">
</body>
<!-- // {{SQL CARBON EDIT}} -->
<script src="../../../../sql/parts/grid/load/loadJquery.js"></script>
<script src="../../../../../node_modules/slickgrid/lib/jquery.event.drag-2.3.0.js"></script>
<script src="../../../../../node_modules/slickgrid/lib/jquery-ui-1.9.2.js"></script>
<!-- Startup via workbench.js -->
<script src="workbench.js"></script>
</html>

View File

@@ -0,0 +1,161 @@
/*---------------------------------------------------------------------------------------------
* 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';
const perf = require('../../../base/common/performance');
perf.mark('renderer/started');
const bootstrapWindow = require('../../../../bootstrap-window');
// Setup shell environment
process['lazyEnv'] = getLazyEnv();
// {{SQL CARBON EDIT}}
/* eslint-disable */
// SQL global imports
const _ = require('underscore')._;
require('slickgrid/slick.core');
const Slick = window.Slick;
require('slickgrid/slick.grid');
require('slickgrid/slick.editors');
require('slickgrid/slick.dataview');
require('reflect-metadata');
require('zone.js');
// {{SQL CARBON EDIT}} - End
// Load workbench main
bootstrapWindow.load([
'vs/workbench/workbench.main',
'vs/nls!vs/workbench/workbench.main',
'vs/css!vs/workbench/workbench.main'
],
function (workbench, configuration) {
perf.mark('didLoadWorkbenchMain');
return process['lazyEnv'].then(function () {
perf.mark('main/startup');
// @ts-ignore
return require('vs/workbench/electron-browser/main').startup(configuration);
});
}, {
removeDeveloperKeybindingsAfterLoad: true,
canModifyDOM: function (windowConfig) {
showPartsSplash(windowConfig);
},
beforeLoaderConfig: function (windowConfig, loaderConfig) {
loaderConfig.recordStats = !!windowConfig.performance;
if (loaderConfig.nodeCachedData) {
const onNodeCachedData = window['MonacoEnvironment'].onNodeCachedData = [];
loaderConfig.nodeCachedData.onData = function () {
onNodeCachedData.push(arguments);
};
}
},
beforeRequire: function () {
perf.mark('willLoadWorkbenchMain');
}
});
/**
* @param {object} configuration
*/
function showPartsSplash(configuration) {
perf.mark('willShowPartsSplash');
let data;
try {
if (!process.env['VSCODE_TEST_STORAGE_MIGRATION']) {
// TODO@Ben remove me after a while
perf.mark('willReadLocalStorage');
let raw = window.localStorage.getItem('storage://global/parts-splash-data');
perf.mark('didReadLocalStorage');
data = JSON.parse(raw);
} else {
data = JSON.parse(configuration.partsSplashData);
}
} catch (e) {
// ignore
}
// high contrast mode has been turned on from the outside, e.g OS -> ignore stored colors and layouts
if (data && configuration.highContrast && data.baseTheme !== 'hc-black') {
data = undefined;
}
// developing an extension -> ignore stored layouts
if (data && configuration.extensionDevelopmentPath) {
data.layoutInfo = undefined;
}
// minimal color configuration (works with or without persisted data)
const baseTheme = data ? data.baseTheme : configuration.highContrast ? 'hc-black' : 'vs-dark';
const shellBackground = data ? data.colorInfo.editorBackground : configuration.highContrast ? '#000000' : '#1E1E1E';
const shellForeground = data ? data.colorInfo.foreground : configuration.highContrast ? '#FFFFFF' : '#CCCCCC';
const style = document.createElement('style');
style.className = 'initialShellColors';
document.head.appendChild(style);
document.body.className = `monaco-shell ${baseTheme}`;
style.innerHTML = `.monaco-shell { background-color: ${shellBackground}; color: ${shellForeground}; }`;
if (data && data.layoutInfo) {
// restore parts if possible (we might not always store layout info)
const { id, layoutInfo, colorInfo } = data;
const splash = document.createElement('div');
splash.id = id;
// ensure there is enough space
layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth));
if (configuration.folderUri || configuration.workspace) {
// folder or workspace -> status bar color, sidebar
splash.innerHTML = `
<div style="position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;"></div>
<div style="position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};"></div>
<div style="position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};"></div>
<div style="position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${colorInfo.statusBarBackground};"></div>
`;
} else {
// empty -> speical status bar color, no sidebar
splash.innerHTML = `
<div style="position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;"></div>
<div style="position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};"></div>
<div style="position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${colorInfo.statusBarNoFolderBackground};"></div>
`;
}
document.body.appendChild(splash);
}
perf.mark('didShowPartsSplash');
}
/**
* @returns {Promise<void>}
*/
function getLazyEnv() {
// @ts-ignore
const ipc = require('electron').ipcRenderer;
return new Promise(function (resolve) {
const handle = setTimeout(function () {
resolve();
console.warn('renderer did not receive lazyEnv in time');
}, 10000);
ipc.once('vscode:acceptShellEnv', function (event, shellEnv) {
clearTimeout(handle);
bootstrapWindow.assign(process.env, shellEnv);
// @ts-ignore
resolve(process.env);
});
ipc.send('vscode:fetchShellEnv');
});
}