mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-24 16:35:55 +01:00
Merge remote-tracking branch 'origin/master' into tyriar/101_hot_exit
This commit is contained in:
@@ -13,7 +13,7 @@ import Event, { buffer } from 'vs/base/common/event';
|
||||
export interface IWindowEventChannel extends IChannel {
|
||||
call(command: 'event:onNewWindowOpen'): TPromise<number>;
|
||||
call(command: 'event:onWindowFocus'): TPromise<number>;
|
||||
call(command: string, arg: any): any;
|
||||
call(command: string, arg?: any): any;
|
||||
}
|
||||
|
||||
export class WindowEventChannel implements IWindowEventChannel {
|
||||
@@ -26,7 +26,7 @@ export class WindowEventChannel implements IWindowEventChannel {
|
||||
this.onWindowFocus = buffer(service.onWindowFocus, true);
|
||||
}
|
||||
|
||||
call(command: string, args: any): any {
|
||||
call(command: string, args?: any): any {
|
||||
switch (command) {
|
||||
case 'event:onNewWindowOpen':
|
||||
return eventToCall(this.onNewWindowOpen);
|
||||
|
||||
@@ -55,7 +55,7 @@ export class LinuxAutoUpdaterImpl extends EventEmitter {
|
||||
if (!update || !update.url || !update.version) {
|
||||
this.emit('update-not-available');
|
||||
} else {
|
||||
this.emit('update-available', null, this.envService.product.downloadUrl);
|
||||
this.emit('update-available', null, this.envService.product.downloadUrl, update.version);
|
||||
}
|
||||
})
|
||||
.then(null, e => {
|
||||
|
||||
@@ -121,6 +121,7 @@ export class EnvService implements IEnvService {
|
||||
extensionDevelopmentPath: normalizePath(argv.extensionDevelopmentPath),
|
||||
extensionTestsPath: normalizePath(argv.extensionTestsPath),
|
||||
'disable-extensions': argv['disable-extensions'],
|
||||
'open-url': argv['open-url'],
|
||||
locale: argv.locale,
|
||||
wait: argv.wait
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ import { VSCodeWindow } from 'vs/code/electron-main/window';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ILogService } from 'vs/code/electron-main/log';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
|
||||
export interface IStartArguments {
|
||||
args: ICommandLineArguments;
|
||||
@@ -52,11 +53,20 @@ export class LaunchService implements ILaunchService {
|
||||
|
||||
constructor(
|
||||
@ILogService private logService: ILogService,
|
||||
@IWindowsService private windowsService: IWindowsService
|
||||
@IWindowsService private windowsService: IWindowsService,
|
||||
@IURLService private urlService: IURLService
|
||||
) {}
|
||||
|
||||
start(args: ICommandLineArguments, userEnv: IProcessEnvironment): TPromise<void> {
|
||||
this.logService.log('Received data from other instance', args, userEnv);
|
||||
this.logService.log('Received data from other instance: ', args, userEnv);
|
||||
|
||||
const openUrlArg = args['open-url'] || [];
|
||||
const openUrl = typeof openUrlArg === 'string' ? [openUrlArg] : openUrlArg;
|
||||
|
||||
if (openUrl.length > 0) {
|
||||
openUrl.forEach(url => this.urlService.open(url));
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
// Otherwise handle in windows service
|
||||
let usedWindows: VSCodeWindow[];
|
||||
|
||||
@@ -26,7 +26,7 @@ export class MainLogService implements ILogService {
|
||||
const { verbose } = this.envService.cliArgs;
|
||||
|
||||
if (verbose) {
|
||||
console.log(`(${new Date().toLocaleTimeString()})`, ...args);
|
||||
console.log(`\x1b[93m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as fs from 'original-fs';
|
||||
import { app, ipcMain as ipc } from 'electron';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
@@ -40,11 +39,16 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { RequestService } from 'vs/platform/request/node/requestService';
|
||||
import * as cp from 'child_process';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { getPathLabel } from 'vs/base/common/labels';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { URLChannel } from 'vs/platform/url/common/urlIpc';
|
||||
import { URLService } from 'vs/platform/url/electron-main/urlService';
|
||||
|
||||
import * as fs from 'original-fs';
|
||||
import * as cp from 'child_process';
|
||||
import * as path from 'path';
|
||||
|
||||
function quit(accessor: ServicesAccessor, error?: Error);
|
||||
function quit(accessor: ServicesAccessor, message?: string);
|
||||
function quit(accessor: ServicesAccessor, arg?: any) {
|
||||
@@ -97,8 +101,9 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce
|
||||
}
|
||||
});
|
||||
|
||||
logService.log('### VSCode main.js ###');
|
||||
logService.log(envService.appRoot, envService.cliArgs);
|
||||
logService.log('Starting VS Code in verbose mode');
|
||||
logService.log(`from: ${envService.appRoot}`);
|
||||
logService.log('args:', envService.cliArgs);
|
||||
|
||||
// Setup Windows mutex
|
||||
let windowsMutex: Mutex = null;
|
||||
@@ -122,7 +127,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce
|
||||
const electronIpcServer = new ElectronIPCServer(ipc);
|
||||
|
||||
// Register Electron IPC services
|
||||
const urlService = instantiationService.createInstance(URLService);
|
||||
const urlService = accessor.get(IURLService);
|
||||
const urlChannel = instantiationService.createInstance(URLChannel, urlService);
|
||||
electronIpcServer.registerChannel('url', urlChannel);
|
||||
|
||||
@@ -194,25 +199,54 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce
|
||||
|
||||
// Install JumpList on Windows
|
||||
if (platform.isWindows) {
|
||||
app.setJumpList([
|
||||
{
|
||||
type: 'tasks',
|
||||
items: [
|
||||
{
|
||||
const jumpList: Electron.JumpListCategory[] = [];
|
||||
|
||||
// Tasks
|
||||
jumpList.push({
|
||||
type: 'tasks',
|
||||
items: [
|
||||
{
|
||||
type: 'task',
|
||||
title: nls.localize('newWindow', "New Window"),
|
||||
description: nls.localize('newWindowDesc', "Opens a new window"),
|
||||
program: process.execPath,
|
||||
args: '-n', // force new window
|
||||
iconPath: process.execPath,
|
||||
iconIndex: 0
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Recent Folders
|
||||
const folders = windowsService.getRecentPathsList().folders;
|
||||
if (folders.length > 0) {
|
||||
jumpList.push({
|
||||
type: 'custom',
|
||||
name: 'Recent Folders',
|
||||
items: windowsService.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => {
|
||||
return <Electron.JumpListItem>{
|
||||
type: 'task',
|
||||
title: nls.localize('newWindow', "New Window"),
|
||||
description: nls.localize('newWindowDesc', "Opens a new window"),
|
||||
title: getPathLabel(folder),
|
||||
description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))),
|
||||
program: process.execPath,
|
||||
args: '-n', // force new window
|
||||
iconPath: process.execPath,
|
||||
args: folder, // open folder,
|
||||
iconPath: 'explorer.exe', // simulate folder icon
|
||||
iconIndex: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'recent' // this enables to show files in the "recent" category
|
||||
}
|
||||
]);
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Recent
|
||||
jumpList.push({
|
||||
type: 'recent' // this enables to show files in the "recent" category
|
||||
});
|
||||
|
||||
try {
|
||||
app.setJumpList(jumpList);
|
||||
} catch (error) {
|
||||
logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors
|
||||
}
|
||||
}
|
||||
|
||||
// Setup auto update
|
||||
@@ -424,6 +458,7 @@ function start(): void {
|
||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||
services.set(IUpdateService, new SyncDescriptor(UpdateManager));
|
||||
services.set(IBackupService, new SyncDescriptor(BackupService));
|
||||
services.set(IURLService, new SyncDescriptor(URLService, args['open-url']));
|
||||
|
||||
const instantiationService = new InstantiationService(services);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as os from 'os';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { IEnvService } from 'vs/code/electron-main/env';
|
||||
@@ -19,23 +18,6 @@ import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/co
|
||||
import { IUpdateService, State as UpdateState } from 'vs/code/electron-main/update-manager';
|
||||
import { Keybinding } from 'vs/base/common/keybinding';
|
||||
import product from 'vs/platform/product';
|
||||
import pkg from 'vs/platform/package';
|
||||
|
||||
export function generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string): string {
|
||||
const osVersion = `${os.type()} ${os.arch()} ${os.release()}`;
|
||||
const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&';
|
||||
const body = encodeURIComponent(
|
||||
`- VSCode Version: ${name} ${version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})
|
||||
- OS Version: ${osVersion}
|
||||
|
||||
Steps to Reproduce:
|
||||
|
||||
1.
|
||||
2.`
|
||||
);
|
||||
|
||||
return `${baseUrl}${queryStringPrefix}body=${body}`;
|
||||
}
|
||||
|
||||
interface IResolvedKeybinding {
|
||||
id: string;
|
||||
@@ -469,7 +451,7 @@ export class VSCodeMenu {
|
||||
|
||||
const find = this.createMenuItem(nls.localize({ key: 'miFind', comment: ['&& denotes a mnemonic'] }, "&&Find"), 'actions.find');
|
||||
const replace = this.createMenuItem(nls.localize({ key: 'miReplace', comment: ['&& denotes a mnemonic'] }, "&&Replace"), 'editor.action.startFindReplaceAction');
|
||||
const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.view.search');
|
||||
const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.action.findInFiles');
|
||||
const replaceInFiles = this.createMenuItem(nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files"), 'workbench.action.replaceInFiles');
|
||||
|
||||
[
|
||||
@@ -511,6 +493,7 @@ export class VSCodeMenu {
|
||||
const toggleStatusbar = this.createMenuItem(nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar"), 'workbench.action.toggleStatusbarVisibility');
|
||||
|
||||
const toggleWordWrap = this.createMenuItem(nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap"), 'editor.action.toggleWordWrap');
|
||||
const toggleRenderWhitespace = this.createMenuItem(nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), 'editor.action.toggleRenderWhitespace');
|
||||
const toggleRenderControlCharacters = this.createMenuItem(nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), 'editor.action.toggleRenderControlCharacter');
|
||||
|
||||
|
||||
@@ -542,6 +525,7 @@ export class VSCodeMenu {
|
||||
toggleStatusbar,
|
||||
__separator__(),
|
||||
toggleWordWrap,
|
||||
toggleRenderWhitespace,
|
||||
toggleRenderControlCharacters,
|
||||
__separator__(),
|
||||
zoomIn,
|
||||
@@ -647,15 +631,24 @@ export class VSCodeMenu {
|
||||
}
|
||||
});
|
||||
|
||||
const issueUrl = generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date);
|
||||
let reportIssuesItem: Electron.MenuItem = null;
|
||||
if (this.envService.product.reportIssueUrl) {
|
||||
const label = nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues");
|
||||
|
||||
if (this.windowsService.getWindowCount() > 0) {
|
||||
reportIssuesItem = this.createMenuItem(label, 'workbench.action.reportIssues');
|
||||
} else {
|
||||
reportIssuesItem = new MenuItem({ label: mnemonicLabel(label), click: () => this.openUrl(product.reportIssueUrl, 'openReportIssues') });
|
||||
}
|
||||
}
|
||||
|
||||
arrays.coalesce([
|
||||
this.envService.product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(this.envService.product.documentationUrl, 'openDocumentationUrl') }) : null,
|
||||
this.envService.product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.openUrl(this.envService.product.releaseNotesUrl, 'openReleaseNotesUrl') }) : null,
|
||||
this.envService.product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes') }) : null,
|
||||
(this.envService.product.documentationUrl || this.envService.product.releaseNotesUrl) ? __separator__() : null,
|
||||
this.envService.product.twitterUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(this.envService.product.twitterUrl, 'openTwitterUrl') }) : null,
|
||||
this.envService.product.requestFeatureUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(this.envService.product.requestFeatureUrl, 'openUserVoiceUrl') }) : null,
|
||||
this.envService.product.reportIssueUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues")), click: () => this.openUrl(issueUrl, 'openReportIssues') }) : null,
|
||||
reportIssuesItem,
|
||||
(this.envService.product.twitterUrl || this.envService.product.requestFeatureUrl || this.envService.product.reportIssueUrl) ? __separator__() : null,
|
||||
this.envService.product.licenseUrl ? new MenuItem({
|
||||
label: mnemonicLabel(nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "&&View License")), click: () => {
|
||||
@@ -679,7 +672,7 @@ export class VSCodeMenu {
|
||||
}) : null,
|
||||
(this.envService.product.licenseUrl || this.envService.product.privacyStatementUrl) ? __separator__() : null,
|
||||
toggleDevToolsItem,
|
||||
platform.isWindows ? showAccessibilityOptions : null
|
||||
platform.isWindows && product.quality !== 'stable' ? showAccessibilityOptions : null
|
||||
]).forEach((item) => helpMenu.append(item));
|
||||
|
||||
if (!platform.isMacintosh) {
|
||||
@@ -752,10 +745,10 @@ export class VSCodeMenu {
|
||||
}
|
||||
|
||||
const options: Electron.MenuItemOptions = {
|
||||
label: label,
|
||||
label,
|
||||
accelerator: this.getAccelerator(actionId),
|
||||
click: click,
|
||||
enabled: enabled
|
||||
click,
|
||||
enabled
|
||||
};
|
||||
|
||||
return new MenuItem(options);
|
||||
|
||||
@@ -108,8 +108,8 @@ export class UpdateManager extends EventEmitter implements IUpdateService {
|
||||
this.setState(State.CheckingForUpdate);
|
||||
});
|
||||
|
||||
this.raw.on('update-available', (event, url: string) => {
|
||||
this.emit('update-available', url);
|
||||
this.raw.on('update-available', (event, url: string, version: string) => {
|
||||
this.emit('update-available', url, version);
|
||||
|
||||
let data: IUpdate = null;
|
||||
|
||||
|
||||
@@ -323,6 +323,15 @@ export class VSCodeWindow {
|
||||
this._lastFocusTime = Date.now();
|
||||
});
|
||||
|
||||
// Window Fullscreen
|
||||
this._win.on('enter-full-screen', () => {
|
||||
this.sendWhenReady('vscode:enterFullScreen');
|
||||
});
|
||||
|
||||
this._win.on('leave-full-screen', () => {
|
||||
this.sendWhenReady('vscode:leaveFullScreen');
|
||||
});
|
||||
|
||||
// Window Failed to load
|
||||
this._win.webContents.on('did-fail-load', (event: Event, errorCode: string, errorDescription: string) => {
|
||||
console.warn('[electron event]: fail to load, ', errorDescription);
|
||||
|
||||
@@ -495,9 +495,9 @@ export class WindowsManager implements IWindowsService {
|
||||
}
|
||||
});
|
||||
|
||||
this.updateService.on('update-available', (url: string) => {
|
||||
this.updateService.on('update-available', (url: string, version: string) => {
|
||||
if (url) {
|
||||
this.sendToFocused('vscode:update-available', url);
|
||||
this.sendToFocused('vscode:update-available', url, version);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -733,7 +733,7 @@ export class WindowsManager implements IWindowsService {
|
||||
|
||||
// Remember in recent document list (unless this opens for extension development)
|
||||
// Also do not add paths when files are opened for diffing, only if opened individually
|
||||
if (!openConfig.cli.extensionDevelopmentPath && !openConfig.cli.diff) {
|
||||
if (!usedWindows.some(w => w.isPluginDevelopmentHost) && !openConfig.cli.diff) {
|
||||
iPathsToOpen.forEach(iPath => {
|
||||
if (iPath.filePath || iPath.workspacePath) {
|
||||
app.addRecentDocument(iPath.filePath || iPath.workspacePath);
|
||||
|
||||
@@ -41,12 +41,18 @@ export function main(argv: string[]): TPromise<void> {
|
||||
'VSCODE_CLI': '1',
|
||||
'ELECTRON_NO_ATTACH_CONSOLE': '1'
|
||||
});
|
||||
|
||||
delete env['ELECTRON_RUN_AS_NODE'];
|
||||
|
||||
let options = {
|
||||
if (args.verbose) {
|
||||
env['ELECTRON_ENABLE_LOGGING'] = '1';
|
||||
}
|
||||
|
||||
const options = {
|
||||
detached: true,
|
||||
env,
|
||||
};
|
||||
|
||||
if (!args.verbose) {
|
||||
options['stdio'] = 'ignore';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user