diff --git a/scripts/code.bat b/scripts/code.bat index ee66e316c0479bba18b535ae53134cc3a49e3142..16ef475d615aa65062069cd48b49752ff21bd4f8 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -9,6 +9,9 @@ if not exist node_modules call .\scripts\npm.bat install :: Get electron node .\node_modules\gulp\bin\gulp.js electron +:: Build +if not exist out node .\node_modules\gulp\bin\gulp.js compile + :: Configuration set NODE_ENV=development set VSCODE_DEV=1 diff --git a/scripts/code.sh b/scripts/code.sh index cad06c7ccaac393058a79d9b28624b8faa174741..ba92a3fe5e6baee058b94899124ef135671af356 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -16,6 +16,9 @@ function code() { # Get electron node node_modules/gulp/bin/gulp.js electron + # Build + test -d out || gulp compile + # Configuration export NODE_ENV=development export VSCODE_DEV=1 diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 31038fa56dc1d608e5cd659059d4b28b206f050e..513203741e1f6a2c969fc134f7da7a1c536b771b 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -55,7 +55,6 @@ var globals = (typeof self === 'object' ? self : global); var userAgent = globals.navigator ? globals.navigator.userAgent : ''; var isTest = !!globals.isTest; -var isPseudo = globals.document && globals.document.URL.match(/[^\?]*\?[^\#]*pseudo=true/); // DOCUMENTED FOR FUTURE REFERENCE: // When running IE11 in IE10 document mode, the code below will identify the browser as being IE10, diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 29fd964ea8a17af26f4a3d52723676dee77db0ad..88ac5bee77959fe327f2b1db9ab6cbddeeadc021 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1046,25 +1046,6 @@ export function removeScriptTags(html:string):string { return div.innerHTML; }; -export function parseSearch():{[key:string]:string} { - var result:{[key:string]:string} = {}; - var search = window.location.search; - if (search) { - var params = search.split(/[?&]/); - for (var i = 0; i < params.length; i++) { - var param = params[i]; - if (param) { - var keyValue = param.split('='); - if (keyValue.length === 2) { - result[keyValue[0]] = decodeURIComponent(keyValue[1]); - } - } - } - } - - return result; -} - export function append(parent: HTMLElement, child: T): T { parent.appendChild(child); return child; diff --git a/src/vs/base/common/flags.ts b/src/vs/base/common/flags.ts index 779cd213d0f415786b4d990c27489a6319d51876..a442271d0457d47b06fdd530d94671d37bc8bb74 100644 --- a/src/vs/base/common/flags.ts +++ b/src/vs/base/common/flags.ts @@ -6,16 +6,7 @@ import { globals } from 'vs/base/common/platform'; -function getWorkersCount(): number { - var defaultValue = 2; - var url_matches = (globals.location ? globals.location.search : '').match(/monaco-workers=(\d+)/i); - if (url_matches) { - defaultValue = parseInt(url_matches[1], 10); - } - return environment('workersCount', defaultValue); -} - -export const workersCount = getWorkersCount(); +export const workersCount = environment('workersCount', 2); export const enableTasks = environment('enableTasks'); export const enableSendASmile = environment('enableSendASmile'); export const enableJavaScriptRewriting = environment('enableJavaScriptRewriting'); diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 7706c3a752b2fe83e842e87395b7be043693c200..0a6328c8920fc4a53556d70ca2698a16c57ab88a 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -174,7 +174,7 @@ export default class URI { var ret = URI._parse(path); if (ret.scheme || ret.fragment || ret.query) { - throw new Error(); + throw new Error(`Path ${ path } contains a scheme, fragment or a query. Can not convert it to a file uri.`); } ret = ret.with('file', undefined, diff --git a/src/vs/nls.js b/src/vs/nls.js index 90214658a15bcafc5f915652b9fc9a8e5d35d779..3687ff29b8a1452bd43eb324e729927c66970de5 100644 --- a/src/vs/nls.js +++ b/src/vs/nls.js @@ -22,7 +22,7 @@ var NLSLoaderPlugin; var global = _nlsPluginGlobal; var Resources = global.Plugin && global.Plugin.Resources ? global.Plugin.Resources : undefined; var DEFAULT_TAG = 'i-default'; - var IS_PSEUDO = (global && global.document && global.document.URL.match(/[^\?]*\?[^\#]*pseudo=true/)); + var IS_PSEUDO = (global && global.document && global.document.location && global.document.location.hash.indexOf('pseudo=true') >= 0); var slice = Array.prototype.slice; function _format(message, args) { var result; diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 9cd4bd4071ebe2341e788475e525221a5b7a3b95..c809ce7d63f2745af0cc20f7e90958b959826812 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -34,7 +34,6 @@ import {WorkbenchLayout, LayoutOptions} from 'vs/workbench/browser/layout'; import {IActionBarRegistry, Extensions as ActionBarExtensions} from 'vs/workbench/browser/actionBarRegistry'; import {IViewletRegistry, Extensions as ViewletExtensions} from 'vs/workbench/browser/viewlet'; import {QuickOpenController} from 'vs/workbench/browser/parts/quickopen/quickOpenController'; -import {WorkspaceStats} from 'vs/platform/telemetry/common/workspaceStats'; import {getServices} from 'vs/platform/instantiation/common/extensions'; import {AbstractKeybindingService} from 'vs/platform/keybinding/browser/keybindingServiceImpl'; import {UntitledEditorService, IUntitledEditorService} from 'vs/workbench/services/untitled/browser/untitledEditorService'; @@ -71,6 +70,7 @@ interface WorkbenchParams { export interface IWorkbenchCallbacks { onServicesCreated?: () => void; + onWorkbenchStarted?: () => void; } /** @@ -247,26 +247,9 @@ export class Workbench implements IPartService { this.eventService.emit(EventType.WORKBENCH_CREATED); this.creationPromiseComplete(true); - // Log to telemetry service - let windowSize = { - innerHeight: window.innerHeight, - innerWidth: window.innerWidth, - outerHeight: window.outerHeight, - outerWidth: window.outerWidth - }; - - this.telemetryService.publicLog('workspaceLoad', - { - userAgent: navigator.userAgent, - windowSize: windowSize, - autoSaveEnabled: this.contextService.isAutoSaveEnabled && this.contextService.isAutoSaveEnabled(), - emptyWorkbench: !this.contextService.getWorkspace(), - customKeybindingsCount: this.keybindingService.customKeybindingsCount(), - theme: this.currentTheme - }); - - let workspaceStats: WorkspaceStats = this.instantiationService.createInstance(WorkspaceStats); - workspaceStats.reportWorkspaceTags(); + if (this.callbacks && this.callbacks.onWorkbenchStarted) { + this.callbacks.onWorkbenchStarted(); + } }, errors.onUnexpectedError); } catch (error) { diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 6046a64f19cce6f75e853eaace22534f55d58566..c446bc8c553028d9f351f0988dcb05522d23f936 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -14,7 +14,7 @@ import 'vs/css!vs/workbench/browser/media/vs-theme'; import 'vs/css!vs/workbench/browser/media/vs-dark-theme'; import 'vs/css!vs/workbench/browser/media/hc-black-theme'; -import {Promise,TPromise} from 'vs/base/common/winjs.base'; +import {Promise, TPromise} from 'vs/base/common/winjs.base'; import {Dimension, Builder, $} from 'vs/base/browser/builder'; import objects = require('vs/base/common/objects'); import env = require('vs/base/common/flags'); @@ -32,6 +32,7 @@ import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {ElectronTelemetryService} from 'vs/platform/telemetry/electron-browser/electronTelemetryService'; import {ElectronIntegration} from 'vs/workbench/electron-browser/integration'; import {Update} from 'vs/workbench/electron-browser/update'; +import {WorkspaceStats} from 'vs/platform/telemetry/common/workspaceStats'; import {IWindowService, WindowService} from 'vs/workbench/services/window/electron-browser/windowService'; import {MessageService} from 'vs/workbench/services/message/electron-browser/messageService'; import {RequestService} from 'vs/workbench/services/request/node/requestService'; @@ -146,7 +147,7 @@ export function getDelayedService(clientPromise: TPromise, ser return servicePromise().then(service => service[key](...args)); } }); - }, {}); + }, {}); } /** @@ -154,12 +155,15 @@ export function getDelayedService(clientPromise: TPromise, ser * With the Shell being the top level element in the page, it is also responsible for driving the layouting. */ export class WorkbenchShell { - private storageServiceInstance: IStorageService; - private messageServiceInstance: IMessageService; - private contextViewServiceInstance: ContextViewService; - private windowServiceInstance: IWindowService; - private threadServiceInstance: MainThreadService; + private storageService: IStorageService; + private messageService: IMessageService; + private contextViewService: ContextViewService; + private windowService: IWindowService; + private threadService: MainThreadService; private themeService: IThemeService; + private contextService: WorkspaceContextService; + private telemetryService: ElectronTelemetryService; + private keybindingService: PluginWorkbenchKeybindingService; private container: HTMLElement; private toUnbind: { (): void; }[]; @@ -208,6 +212,9 @@ export class WorkbenchShell { this.workbench.startup({ onServicesCreated: () => { this.initPluginSystem(); + }, + onWorkbenchStarted: () => { + this.onWorkbenchStarted(); } }); @@ -229,88 +236,112 @@ export class WorkbenchShell { return workbenchContainer; } + private onWorkbenchStarted(): void { + + // Log to telemetry service + let windowSize = { + innerHeight: window.innerHeight, + innerWidth: window.innerWidth, + outerHeight: window.outerHeight, + outerWidth: window.outerWidth + }; + + this.telemetryService.publicLog('workspaceLoad', + { + userAgent: navigator.userAgent, + windowSize: windowSize, + autoSaveEnabled: this.contextService.isAutoSaveEnabled && this.contextService.isAutoSaveEnabled(), + emptyWorkbench: !this.contextService.getWorkspace(), + customKeybindingsCount: this.keybindingService.customKeybindingsCount(), + theme: this.currentTheme + }); + + let workspaceStats: WorkspaceStats = this.workbench.getInstantiationService().createInstance(WorkspaceStats); + workspaceStats.reportWorkspaceTags(); + } + private initInstantiationService(): IInstantiationService { - let eventServiceInstance = new EventService(); + let eventService = new EventService(); - let contextServiceInstance = new WorkspaceContextService(eventServiceInstance, this.workspace, this.configuration, this.options); - contextServiceInstance.getConfiguration().additionalWorkerServices = [ + this.contextService = new WorkspaceContextService(eventService, this.workspace, this.configuration, this.options); + this.contextService.getConfiguration().additionalWorkerServices = [ { serviceId: 'requestService', moduleName: 'vs/workbench/services/request/common/requestService', ctorName: 'WorkerRequestService' } ]; - this.windowServiceInstance = new WindowService(); - this.storageServiceInstance = new Storage(contextServiceInstance); + this.windowService = new WindowService(); + this.storageService = new Storage(this.contextService); // no telemetry in a window for plugin development! let enableTelemetry = this.configuration.env.isBuilt && !this.configuration.env.pluginDevelopmentPath ? !!this.configuration.env.enableTelemetry : false; - let telemetryServiceInstance = new ElectronTelemetryService(this.storageServiceInstance, { enableTelemetry: enableTelemetry, version: this.configuration.env.version, commitHash: this.configuration.env.commitHash }); + this.telemetryService = new ElectronTelemetryService(this.storageService, { enableTelemetry: enableTelemetry, version: this.configuration.env.version, commitHash: this.configuration.env.commitHash }); - let keybindingServiceInstance = new PluginWorkbenchKeybindingService(contextServiceInstance, eventServiceInstance, telemetryServiceInstance, window); + this.keybindingService = new PluginWorkbenchKeybindingService(this.contextService, eventService, this.telemetryService, window); - this.messageServiceInstance = new MessageService(contextServiceInstance, this.windowServiceInstance, telemetryServiceInstance, keybindingServiceInstance); - keybindingServiceInstance.setMessageService(this.messageServiceInstance); + this.messageService = new MessageService(this.contextService, this.windowService, this.telemetryService, this.keybindingService); + this.keybindingService.setMessageService(this.messageService); - let configServiceInstance = new ConfigurationService( - contextServiceInstance, - eventServiceInstance + let configService = new ConfigurationService( + this.contextService, + eventService ); - let fileServiceInstance = new FileService( - configServiceInstance, - eventServiceInstance, - contextServiceInstance + let fileService = new FileService( + configService, + eventService, + this.contextService ); - this.contextViewServiceInstance = new ContextViewService(this.container, telemetryServiceInstance, this.messageServiceInstance); + this.contextViewService = new ContextViewService(this.container, this.telemetryService, this.messageService); - let lifecycleServiceInstance = new LifecycleService(this.messageServiceInstance, this.windowServiceInstance); - lifecycleServiceInstance.onShutdown.add(() => fileServiceInstance.dispose()); + let lifecycleService = new LifecycleService(this.messageService, this.windowService); + lifecycleService.onShutdown.add(() => fileService.dispose()); - this.threadServiceInstance = new MainThreadService(contextServiceInstance, this.messageServiceInstance, this.windowServiceInstance); - lifecycleServiceInstance.onShutdown.add(() => this.threadServiceInstance.dispose()); + this.threadService = new MainThreadService(this.contextService, this.messageService, this.windowService); + lifecycleService.onShutdown.add(() => this.threadService.dispose()); - let requestServiceInstance = new RequestService( - contextServiceInstance, - configServiceInstance, - telemetryServiceInstance + let requestService = new RequestService( + this.contextService, + configService, + this.telemetryService ); - this.threadServiceInstance.registerInstance(requestServiceInstance); - lifecycleServiceInstance.onShutdown.add(() => requestServiceInstance.dispose()); + this.threadService.registerInstance(requestService); + lifecycleService.onShutdown.add(() => requestService.dispose()); - let markerServiceInstance = new MarkerService(this.threadServiceInstance); + let markerService = new MarkerService(this.threadService); - let pluginService = new MainProcessPluginService(contextServiceInstance, this.threadServiceInstance, this.messageServiceInstance, telemetryServiceInstance); - keybindingServiceInstance.setPluginService(pluginService); + let pluginService = new MainProcessPluginService(this.contextService, this.threadService, this.messageService, this.telemetryService); + this.keybindingService.setPluginService(pluginService); - let modelServiceInstance = new ModelServiceImpl(this.threadServiceInstance, markerServiceInstance); - let modeService = new MainThreadModeServiceImpl(this.threadServiceInstance, pluginService, modelServiceInstance); + let modelService = new ModelServiceImpl(this.threadService, markerService); + let modeService = new MainThreadModeServiceImpl(this.threadService, pluginService, modelService); let untitledEditorService = new UntitledEditorService(); this.themeService = new ThemeService(pluginService); let result = createInstantiationService(); - result.addSingleton(ITelemetryService, telemetryServiceInstance); - result.addSingleton(IEventService, eventServiceInstance); - result.addSingleton(IRequestService, requestServiceInstance); - result.addSingleton(IWorkspaceContextService, contextServiceInstance); - result.addSingleton(IContextViewService, this.contextViewServiceInstance); - result.addSingleton(IContextMenuService, new ContextMenuService(this.messageServiceInstance, telemetryServiceInstance)); - result.addSingleton(IMessageService, this.messageServiceInstance); - result.addSingleton(IStorageService, this.storageServiceInstance); - result.addSingleton(ILifecycleService, lifecycleServiceInstance); - result.addSingleton(IThreadService, this.threadServiceInstance); + result.addSingleton(ITelemetryService, this.telemetryService); + result.addSingleton(IEventService, eventService); + result.addSingleton(IRequestService, requestService); + result.addSingleton(IWorkspaceContextService, this.contextService); + result.addSingleton(IContextViewService, this.contextViewService); + result.addSingleton(IContextMenuService, new ContextMenuService(this.messageService, this.telemetryService)); + result.addSingleton(IMessageService, this.messageService); + result.addSingleton(IStorageService, this.storageService); + result.addSingleton(ILifecycleService, lifecycleService); + result.addSingleton(IThreadService, this.threadService); result.addSingleton(IPluginService, pluginService); result.addSingleton(IModeService, modeService); - result.addSingleton(IFileService, fileServiceInstance); + result.addSingleton(IFileService, fileService); result.addSingleton(IUntitledEditorService, untitledEditorService); - result.addSingleton(ISearchService, new SearchService(modelServiceInstance, untitledEditorService, contextServiceInstance, configServiceInstance)); - result.addSingleton(IWindowService, this.windowServiceInstance); - result.addSingleton(IConfigurationService, configServiceInstance); - result.addSingleton(IKeybindingService, keybindingServiceInstance); - result.addSingleton(IMarkerService, markerServiceInstance); - result.addSingleton(IModelService, modelServiceInstance); + result.addSingleton(ISearchService, new SearchService(modelService, untitledEditorService, this.contextService, configService)); + result.addSingleton(IWindowService, this.windowService); + result.addSingleton(IConfigurationService, configService); + result.addSingleton(IKeybindingService, this.keybindingService); + result.addSingleton(IMarkerService, markerService); + result.addSingleton(IModelService, modelService); result.addSingleton(ICodeEditorService, new CodeEditorServiceImpl()); result.addSingleton(IThemeService, this.themeService); - result.addSingleton(IActionsService, new ActionsService(pluginService, keybindingServiceInstance)); + result.addSingleton(IActionsService, new ActionsService(pluginService, this.keybindingService)); return result; @@ -318,24 +349,24 @@ export class WorkbenchShell { // TODO@Alex, TODO@Joh move this out of here? private initPluginSystem(): void { - this.threadServiceInstance.getRemotable(MainProcessVSCodeAPIHelper); - this.threadServiceInstance.getRemotable(MainThreadDocuments); - this.threadServiceInstance.getRemotable(RemoteTelemetryServiceHelper); + this.threadService.getRemotable(MainProcessVSCodeAPIHelper); + this.threadService.getRemotable(MainThreadDocuments); + this.threadService.getRemotable(RemoteTelemetryServiceHelper); this.workbench.getInstantiationService().createInstance(MainProcessTextMateSyntax); this.workbench.getInstantiationService().createInstance(MainProcessTextMateSnippet); this.workbench.getInstantiationService().createInstance(LanguageConfigurationFileHandler); - this.threadServiceInstance.getRemotable(MainThreadConfiguration); - this.threadServiceInstance.getRemotable(MainThreadQuickOpen); - this.threadServiceInstance.getRemotable(MainThreadStatusBar); + this.threadService.getRemotable(MainThreadConfiguration); + this.threadService.getRemotable(MainThreadQuickOpen); + this.threadService.getRemotable(MainThreadStatusBar); this.workbench.getInstantiationService().createInstance(MainThreadFileSystemEventService); - this.threadServiceInstance.getRemotable(MainThreadCommands); - this.threadServiceInstance.getRemotable(MainThreadOutputService); - this.threadServiceInstance.getRemotable(MainThreadDiagnostics); - this.threadServiceInstance.getRemotable(MainThreadMessageService); - this.threadServiceInstance.getRemotable(MainThreadLanguages); - this.threadServiceInstance.getRemotable(MainThreadWorkspace); - this.threadServiceInstance.getRemotable(MainThreadEditors); - this.threadServiceInstance.getRemotable(MainThreadStorage); + this.threadService.getRemotable(MainThreadCommands); + this.threadService.getRemotable(MainThreadOutputService); + this.threadService.getRemotable(MainThreadDiagnostics); + this.threadService.getRemotable(MainThreadMessageService); + this.threadService.getRemotable(MainThreadLanguages); + this.threadService.getRemotable(MainThreadWorkspace); + this.threadService.getRemotable(MainThreadEditors); + this.threadService.getRemotable(MainThreadStorage); this.threadServiceInstance.getRemotable(MainThreadLanguageFeatures); } @@ -365,15 +396,15 @@ export class WorkbenchShell { this.registerListeners(); // Enable theme support - let themeId = this.storageServiceInstance.get(Preferences.THEME, StorageScope.GLOBAL, null); + let themeId = this.storageService.get(Preferences.THEME, StorageScope.GLOBAL, null); if (!themeId) { themeId = themes.toId(themes.BaseTheme.VS_DARK); - this.storageServiceInstance.store(Preferences.THEME, themeId, StorageScope.GLOBAL); + this.storageService.store(Preferences.THEME, themeId, StorageScope.GLOBAL); } this.setTheme(themeId, false); - this.toUnbind.push(this.storageServiceInstance.addListener(StorageEventType.STORAGE, (e: StorageEvent) => { + this.toUnbind.push(this.storageService.addListener(StorageEventType.STORAGE, (e: StorageEvent) => { if (e.key === Preferences.THEME) { this.setTheme(e.newValue); } @@ -487,8 +518,8 @@ export class WorkbenchShell { console.error(errorMsg); // Show to user if friendly message provided - if (error.friendlyMessage && this.messageServiceInstance) { - this.messageServiceInstance.show(Severity.Error, error.friendlyMessage); + if (error.friendlyMessage && this.messageService) { + this.messageService.show(Severity.Error, error.friendlyMessage); } } @@ -498,7 +529,7 @@ export class WorkbenchShell { let contentsSize = new Dimension(clArea.width, clArea.height); this.contentsContainer.size(contentsSize.width, contentsSize.height); - this.contextViewServiceInstance.layout(); + this.contextViewService.layout(); this.workbench.layout(); } @@ -518,8 +549,8 @@ export class WorkbenchShell { } } - this.contextViewServiceInstance.dispose(); - this.storageServiceInstance.dispose(); + this.contextViewService.dispose(); + this.storageService.dispose(); // Listeners while (this.toUnbind.length) { diff --git a/src/vs/workbench/electron-main/lifecycle.ts b/src/vs/workbench/electron-main/lifecycle.ts index 4d0cbc3f5f671bd512b8308e432789216fc4ae51..b1963df89532b909d2873a84101133a006e0a0d6 100644 --- a/src/vs/workbench/electron-main/lifecycle.ts +++ b/src/vs/workbench/electron-main/lifecycle.ts @@ -133,7 +133,7 @@ export class Lifecycle { c(true); // veto }); - vscodeWindow.win.webContents.send('vscode:beforeUnload', { okChannel: oneTimeOkEvent, cancelChannel: oneTimeCancelEvent }); + vscodeWindow.send('vscode:beforeUnload', { okChannel: oneTimeOkEvent, cancelChannel: oneTimeCancelEvent }); }); } diff --git a/src/vs/workbench/electron-main/menus.ts b/src/vs/workbench/electron-main/menus.ts index 0187db6b3ac33dde7280c45f9022c75acb48174d..c8b51c2b8717a986fbc870e9ffee1c130b25779d 100644 --- a/src/vs/workbench/electron-main/menus.ts +++ b/src/vs/workbench/electron-main/menus.ts @@ -37,7 +37,6 @@ export class VSCodeMenu { private static lastKnownKeybindingsMapStorageKey = 'lastKnownKeybindings'; - private static MAX_RECENT_ENTRIES = 10; private static AUTO_SAVE_DELAY_DEFAULT = 1000; // in ms private static AUTO_SAVE_DISABLED = -1; @@ -119,7 +118,7 @@ export class VSCodeMenu { // Resolve keybindings when workbench window is up if (this.actionIdKeybindingRequests.length) { - win.win.webContents.send('vscode:resolveKeybindings', JSON.stringify(this.actionIdKeybindingRequests)); + win.send('vscode:resolveKeybindings', JSON.stringify(this.actionIdKeybindingRequests)); } } @@ -423,7 +422,7 @@ export class VSCodeMenu { // Folders recentList.folders.forEach((folder, index) => { - if (index < VSCodeMenu.MAX_RECENT_ENTRIES) { + if (index < windows.WindowsManager.MAX_RECENT_ENTRIES) { openRecentMenu.append(this.createOpenRecentMenuItem(folder)); } }); @@ -435,7 +434,7 @@ export class VSCodeMenu { } recentList.files.forEach((file, index) => { - if (index < VSCodeMenu.MAX_RECENT_ENTRIES) { + if (index < windows.WindowsManager.MAX_RECENT_ENTRIES) { openRecentMenu.append(this.createOpenRecentMenuItem(file)); } }); diff --git a/src/vs/workbench/electron-main/window.ts b/src/vs/workbench/electron-main/window.ts index 066fba4d282b8907d1268eb9bb750aaafb78a202..7bd14c3c9961ce7e87ade24f15080800bd2a9542 100644 --- a/src/vs/workbench/electron-main/window.ts +++ b/src/vs/workbench/electron-main/window.ts @@ -294,9 +294,9 @@ export class VSCodeWindow { // Support navigation via mouse buttons 4/5 if (cmd === 'browser-backward') { - this._win.webContents.send('vscode:runAction', 'workbench.action.navigateBack'); + this.send('vscode:runAction', 'workbench.action.navigateBack'); } else if (cmd === 'browser-forward') { - this._win.webContents.send('vscode:runAction', 'workbench.action.navigateForward'); + this.send('vscode:runAction', 'workbench.action.navigateForward'); } }); @@ -532,6 +532,16 @@ export class VSCodeWindow { this.win.setMenuBarVisibility(isFullScreen); } + public sendWhenReady(channel: string, ...args: any[]): void { + this.ready().then(() => { + this.send(channel, ...args); + }); + } + + public send(channel: string, ...args: any[]): void { + this._win.webContents.send(channel, ...args); + } + public dispose(): void { if (this.showTimeoutHandle) { clearTimeout(this.showTimeoutHandle); diff --git a/src/vs/workbench/electron-main/windows.ts b/src/vs/workbench/electron-main/windows.ts index f928b91863feff631a45064b0d42863bf7901752..f7e8ebdb77bcbe3c99aeff7c87067b21b4964559 100644 --- a/src/vs/workbench/electron-main/windows.ts +++ b/src/vs/workbench/electron-main/windows.ts @@ -95,8 +95,9 @@ export class WindowsManager { public static autoSaveDelayStorageKey = 'autoSaveDelay'; public static openedPathsListStorageKey = 'openedPathsList'; - private static workingDirPickerStorageKey = 'pickerWorkingDir'; + public static MAX_RECENT_ENTRIES = 10; + private static workingDirPickerStorageKey = 'pickerWorkingDir'; private static windowsStateStorageKey = 'windowsState'; private static themeStorageKey = 'theme'; // TODO@Ben this key is only used to find out if a window can be shown instantly because of light theme, remove once we have support for bg color @@ -390,13 +391,13 @@ export class WindowsManager { if (!openFilesInNewWindow && lastActiveWindow) { lastActiveWindow.restore(); lastActiveWindow.ready().then((readyWindow) => { - readyWindow.win.webContents.send('vscode:openFiles', { + readyWindow.send('vscode:openFiles', { filesToOpen: filesToOpen, filesToCreate: filesToCreate }); if (extensionsToInstall.length) { - readyWindow.win.webContents.send('vscode:installExtensions', { extensionsToInstall }); + readyWindow.send('vscode:installExtensions', { extensionsToInstall }); } }); } @@ -418,13 +419,13 @@ export class WindowsManager { if (windowsOnWorkspacePath.length > 0) { windowsOnWorkspacePath[0].restore(); // just focus one of them windowsOnWorkspacePath[0].ready().then((readyWindow) => { - readyWindow.win.webContents.send('vscode:openFiles', { + readyWindow.send('vscode:openFiles', { filesToOpen: filesToOpen, filesToCreate: filesToCreate }); if (extensionsToInstall.length) { - readyWindow.win.webContents.send('vscode:installExtensions', { extensionsToInstall }); + readyWindow.send('vscode:installExtensions', { extensionsToInstall }); } }); @@ -567,7 +568,8 @@ export class WindowsManager { // Clear those dupes recentPaths = arrays.distinct(recentPaths); - return recentPaths; + // Make sure it is bounded + return recentPaths.slice(0, WindowsManager.MAX_RECENT_ENTRIES); } private toIPath(anyPath: string, ignoreFileNotFound?: boolean, gotoLineMode?: boolean): window.IPath { @@ -889,9 +891,7 @@ export class WindowsManager { const focusedWindow = this.getFocusedWindow() || this.getLastActiveWindow(); if (focusedWindow) { - focusedWindow.ready().then((readyWindow) => { - readyWindow.win.webContents.send(channel, ...args); - }); + focusedWindow.sendWhenReady(channel, ...args); } } @@ -901,9 +901,7 @@ export class WindowsManager { return; // do not send if we are instructed to ignore it } - w.ready().then((readyWindow) => { - readyWindow.win.webContents.send(channel, payload); - }); + w.sendWhenReady(channel, payload); }); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index 6a2e98b477878381bcd2ab78bd64a78a58e5caca..c7d4e3ed74a6a16bef69e6b9a90bc8bc5ae17628 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -8,12 +8,6 @@ import platform = require('vs/platform/platform'); import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; import service = require('vs/workbench/parts/debug/electron-browser/debugService'); -import { ExtensionOutputHandler } from 'vs/workbench/parts/debug/electron-browser/extensionOutput'; // Register Service -registerSingleton(IDebugService, service.DebugService); - -// Register Extension Output Handler -(platform.Registry.as(Extensions.Workbench)).registerWorkbenchContribution( - ExtensionOutputHandler -); \ No newline at end of file +registerSingleton(IDebugService, service.DebugService); \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index e81bc0f76c985de23ed098d234f6d93df5ad7e2c..7267882fea7ee58390cd3f85809ab4b250ed0f37 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -13,6 +13,7 @@ import uri from 'vs/base/common/uri'; import arrays = require('vs/base/common/arrays'); import actions = require('vs/base/common/actions'); import json = require('vs/base/common/json'); +import types = require('vs/base/common/types'); import errors = require('vs/base/common/errors'); import severity from 'vs/base/common/severity'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; @@ -49,7 +50,8 @@ import { IPluginService, IPluginDescription } from 'vs/platform/plugins/common/p import { IOutputService } from 'vs/workbench/parts/output/common/output'; import { IKeybindingService, IKeybindingContextKey } from 'vs/platform/keybinding/common/keybindingService'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/browser/quickOpenService'; -import { IWindowService } from 'vs/workbench/services/window/electron-browser/windowService'; +import { IWindowService, IBroadcast } from 'vs/workbench/services/window/electron-browser/windowService'; +import { ILogEntry, PLUGIN_LOG_BROADCAST_CHANNEL } from 'vs/workbench/services/thread/electron-browser/threadService'; var DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; var DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -184,6 +186,89 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService lifecycleService.onShutdown.add(this.store, this); lifecycleService.onShutdown.add(this.dispose, this); + + this.windowService.onBroadcast.add(this.onBroadcast, this); + } + + private onBroadcast(broadcast: IBroadcast): void { + let session = this.getActiveSession(); + if (!session || session.getType() !== 'extensionHost') { + return; // we are only intersted if we have an active debug session for extensionHost + } + + // A plugin logged output, show it inside the REPL + if (broadcast.channel === PLUGIN_LOG_BROADCAST_CHANNEL) { + let extensionOutput: ILogEntry = broadcast.payload; + let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; + + let args: any[] = []; + try { + let parsed = JSON.parse(extensionOutput.arguments); + args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); + } catch (error) { + args.push(extensionOutput.arguments); + } + + // Add output for each argument logged + let simpleVals: any[] = []; + for (let i = 0; i < args.length; i++) { + let a = args[i]; + + // Undefined gets printed as 'undefined' + if (typeof a === 'undefined') { + simpleVals.push('undefined'); + } + + // Null gets printed as 'null' + else if (a === null) { + simpleVals.push('null'); + } + + // Objects & Arrays are special because we want to inspect them in the REPL + else if (types.isObject(a) || Array.isArray(a)) { + + // Flush any existing simple values logged + if (simpleVals.length) { + this.logToRepl(simpleVals.join(' '), sev); + simpleVals = []; + } + + // Show object + this.logToRepl(a, sev); + } + + // String: watch out for % replacement directive + // String substitution and formatting @ https://developer.chrome.com/devtools/docs/console + else if (typeof a === 'string') { + let buf = ''; + + for (let j = 0, len = a.length; j < len; j++) { + if (a[j] === '%' && (a[j + 1] === 's' || a[j + 1] === 'i' || a[j + 1] === 'd')) { + i++; // read over substitution + buf += !types.isUndefinedOrNull(args[i]) ? args[i] : ''; // replace + j++; // read over directive + } else { + buf += a[j]; + } + } + + simpleVals.push(buf); + } + + // number or boolean is joined together + else { + simpleVals.push(a); + } + } + + // Flush simple values + if (simpleVals.length) { + this.logToRepl(simpleVals.join(' '), sev); + } + + // Show repl + this.revealRepl(true /* in background */).done(null, errors.onUnexpectedError); + } } private registerSessionListeners(): void { diff --git a/src/vs/workbench/parts/debug/electron-browser/extensionOutput.ts b/src/vs/workbench/parts/debug/electron-browser/extensionOutput.ts deleted file mode 100644 index 83eb9d1e7d973590c9ab53ee24b71858b7f8fddb..0000000000000000000000000000000000000000 --- a/src/vs/workbench/parts/debug/electron-browser/extensionOutput.ts +++ /dev/null @@ -1,115 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; -import errors = require('vs/base/common/errors'); -import types = require('vs/base/common/types'); -import severity from 'vs/base/common/severity'; -import { ILogEntry, PLUGIN_LOG_BROADCAST_CHANNEL } from 'vs/workbench/services/thread/electron-browser/threadService'; -import { IWindowService, IBroadcast } from 'vs/workbench/services/window/electron-browser/windowService'; - -import ipc = require('ipc'); - -export class ExtensionOutputHandler implements IWorkbenchContribution { - - static ID = 'debug.extensionOutputHandler'; - - constructor( - @IDebugService private debugService: IDebugService, - @IWindowService private windowService: IWindowService - ) { - this.registerListeners(); - } - - private registerListeners(): void { - this.windowService.onBroadcast.add(this.onBroadcast, this); - } - - private onBroadcast(broadcast: IBroadcast): void { - let session = this.debugService.getActiveSession(); - if (!session || session.getType() !== 'extensionHost') { - return; // we are only intersted if we have an active debug session for extensionHost - } - - // A plugin logged output, show it inside the REPL - if (broadcast.channel === PLUGIN_LOG_BROADCAST_CHANNEL) { - let extensionOutput: ILogEntry = broadcast.payload; - let sev = extensionOutput.severity === 'warn' ? severity.Warning : extensionOutput.severity === 'error' ? severity.Error : severity.Info; - - let args: any[] = []; - try { - let parsed = JSON.parse(extensionOutput.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(extensionOutput.arguments); - } - - // Add output for each argument logged - let simpleVals: any[] = []; - for (let i = 0; i < args.length; i++) { - let a = args[i]; - - // Undefined gets printed as 'undefined' - if (typeof a === 'undefined') { - simpleVals.push('undefined'); - } - - // Null gets printed as 'null' - else if (a === null) { - simpleVals.push('null'); - } - - // Objects & Arrays are special because we want to inspect them in the REPL - else if (types.isObject(a) || Array.isArray(a)) { - - // Flush any existing simple values logged - if (simpleVals.length) { - this.debugService.logToRepl(simpleVals.join(' '), sev); - simpleVals = []; - } - - // Show object - this.debugService.logToRepl(a, sev); - } - - // String: watch out for % replacement directive - // String substitution and formatting @ https://developer.chrome.com/devtools/docs/console - else if (typeof a === 'string') { - let buf = ''; - - for (let j = 0, len = a.length; j < len; j++) { - if (a[j] === '%' && (a[j + 1] === 's' || a[j + 1] === 'i' || a[j + 1] === 'd')) { - i++; // read over substitution - buf += !types.isUndefinedOrNull(args[i]) ? args[i] : ''; // replace - j++; // read over directive - } else { - buf += a[j]; - } - } - - simpleVals.push(buf); - } - - // number or boolean is joined together - else { - simpleVals.push(a); - } - } - - // Flush simple values - if (simpleVals.length) { - this.debugService.logToRepl(simpleVals.join(' '), sev); - } - - // Show repl - this.debugService.revealRepl(true /* in background */).done(null, errors.onUnexpectedError); - } - } - - public getId(): string { - return ExtensionOutputHandler.ID; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/test/common/replHistory.test.ts b/src/vs/workbench/parts/debug/test/common/replHistory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1da7fe5b94e364aa4e5a9b7d4d6eb6ad357e29c1 --- /dev/null +++ b/src/vs/workbench/parts/debug/test/common/replHistory.test.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert = require('assert'); +import { ReplHistory } from 'vs/workbench/parts/debug/common/replHistory'; + +suite('Debug - Repl History', () => { + var history: ReplHistory; + + setup(() => { + history = new ReplHistory(['one', 'two', 'three', 'four', 'five']); + }); + + teardown(() => { + history = null; + }); + + test('previous and next', () => { + assert.equal(history.previous(), 'five'); + assert.equal(history.previous(), 'four'); + assert.equal(history.previous(), 'three'); + assert.equal(history.previous(), 'two'); + assert.equal(history.previous(), 'one'); + assert.equal(history.previous(), null); + assert.equal(history.next(), 'two'); + assert.equal(history.next(), 'three'); + assert.equal(history.next(), 'four'); + assert.equal(history.next(), 'five'); + }); + + test('evaluated and remember', () => { + history.evaluated('six'); + assert.equal(history.previous(), 'six'); + assert.equal(history.previous(), 'five'); + assert.equal(history.next(), 'six'); + + history.remember('six++', true); + assert.equal(history.next(), 'six++'); + assert.equal(history.previous(), 'six'); + + history.evaluated('seven'); + assert.equal(history.previous(), 'seven'); + assert.equal(history.previous(), 'six'); + }); +});