diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 846b10ecdce..5ecb9a1f315 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -39,7 +39,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.9.0' }, + { name: 'ms-vscode.node-debug', version: '1.9.1' }, { name: 'ms-vscode.node-debug2', version: '1.9.1' } ]; diff --git a/build/monaco/api.js b/build/monaco/api.js index 4cab80a45a9..469b19bd79d 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -188,21 +188,21 @@ function format(text) { } function getDefaultOptions() { return { - IndentSize: 4, - TabSize: 4, - NewLineCharacter: '\r\n', - ConvertTabsToSpaces: true, - IndentStyle: ts.IndentStyle.Block, - InsertSpaceAfterCommaDelimiter: true, - InsertSpaceAfterSemicolonInForStatements: true, - InsertSpaceBeforeAndAfterBinaryOperators: true, - InsertSpaceAfterKeywordsInControlFlowStatements: true, - InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false, - InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, - InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, - InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true, - PlaceOpenBraceOnNewLineForFunctions: false, - PlaceOpenBraceOnNewLineForControlBlocks: false, + indentSize: 4, + tabSize: 4, + newLineCharacter: '\r\n', + convertTabsToSpaces: true, + indentStyle: ts.IndentStyle.Block, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, }; } } diff --git a/build/monaco/api.ts b/build/monaco/api.ts index 2ca2968c6c3..b399d1b1d81 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -217,22 +217,22 @@ function format(text:string): string { function getDefaultOptions(): ts.FormatCodeOptions { return { - IndentSize: 4, - TabSize: 4, - NewLineCharacter: '\r\n', - ConvertTabsToSpaces: true, - IndentStyle: ts.IndentStyle.Block, + indentSize: 4, + tabSize: 4, + newLineCharacter: '\r\n', + convertTabsToSpaces: true, + indentStyle: ts.IndentStyle.Block, - InsertSpaceAfterCommaDelimiter: true, - InsertSpaceAfterSemicolonInForStatements: true, - InsertSpaceBeforeAndAfterBinaryOperators: true, - InsertSpaceAfterKeywordsInControlFlowStatements: true, - InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false, - InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, - InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, - InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true, - PlaceOpenBraceOnNewLineForFunctions: false, - PlaceOpenBraceOnNewLineForControlBlocks: false, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, }; } } diff --git a/extensions/markdown/syntaxes/markdown.tmLanguage b/extensions/markdown/syntaxes/markdown.tmLanguage index 30afb189404..754d0179fb6 100644 --- a/extensions/markdown/syntaxes/markdown.tmLanguage +++ b/extensions/markdown/syntaxes/markdown.tmLanguage @@ -355,7 +355,7 @@ begin - (^|\G)\s*(?=(<[a-zA-Z0-9\-].*>|</[a-zA-Z0-9\-]>)\s*$) + (^|\G)\s*(?=(<[a-zA-Z0-9\-](/?>|\s.*?>)|</[a-zA-Z0-9\-]>)\s*$) patterns diff --git a/extensions/typescript/src/features/codeActionProvider.ts b/extensions/typescript/src/features/codeActionProvider.ts index e0ff2b69412..51a9aed5a67 100644 --- a/extensions/typescript/src/features/codeActionProvider.ts +++ b/extensions/typescript/src/features/codeActionProvider.ts @@ -5,7 +5,7 @@ 'use strict'; -import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit } from 'vscode'; +import { CodeActionProvider, TextDocument, Range, CancellationToken, CodeActionContext, Command, commands, Uri, workspace, WorkspaceEdit, TextEdit, Position } from 'vscode'; import * as Proto from '../protocol'; import { ITypescriptServiceClient } from '../typescriptService'; @@ -46,7 +46,7 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider public provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Thenable { const file = this.client.asAbsolutePath(document.uri); if (!file) { - return Promise.resolve(null); + return Promise.resolve([]); } const source: Source = { @@ -99,11 +99,29 @@ export default class TypeScriptCodeActionProvider implements CodeActionProvider private onCodeAction(source: Source, workspaceEdit: WorkspaceEdit) { workspace.applyEdit(workspaceEdit).then(success => { if (!success) { - return Promise.reject(null); + return Promise.reject(false); } + + let firstEdit: TextEdit | null = null; + for (const [uri, edits] of workspaceEdit.entries()) { + if (uri.fsPath === source.uri.fsPath) { + firstEdit = edits[0]; + break; + } + } + + if (!firstEdit) { + return true; + } + + const newLines = firstEdit.newText.match(/\n/g); + const editedRange = new Range( + new Position(firstEdit.range.start.line, 0), + new Position(firstEdit.range.end.line + 1 + (newLines ? newLines.length : 0), 0)); + // TODO: Workaround for https://github.com/Microsoft/TypeScript/issues/12249 // apply formatting to the source range until TS returns formatted results - return commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, source.range, {}).then((edits: TextEdit[]) => { + return commands.executeCommand('vscode.executeFormatRangeProvider', source.uri, editedRange, {}).then((edits: TextEdit[]) => { if (!edits || !edits.length) { return false; } diff --git a/extensions/typescript/src/features/completionItemProvider.ts b/extensions/typescript/src/features/completionItemProvider.ts index 1894dab23ba..71cb92ffd94 100644 --- a/extensions/typescript/src/features/completionItemProvider.ts +++ b/extensions/typescript/src/features/completionItemProvider.ts @@ -119,7 +119,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Promise { if (this.typingsStatus.isAcquiringTypings) { - return Promise.reject({ + return Promise.reject({ label: localize('acquiringTypingsLabel', 'Acquiring typings...'), detail: localize('acquiringTypingsDetail', 'Acquiring typings definitions for IntelliSense.') }); diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index ad18e62f4c3..12e36d958e9 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -346,17 +346,20 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient switch (selected.id) { case MessageAction.useLocal: let pathValue = './node_modules/typescript/lib'; - tsConfig.update('tsdk', pathValue, false); - window.showInformationMessage(localize('updatedtsdk', 'Updated workspace setting \'typescript.tsdk\' to {0}', pathValue)); + tsConfig.update('tsdk', pathValue, false).then( + () => window.showInformationMessage(localize('updatedtsdk', 'Updated workspace setting \'typescript.tsdk\' to {0}', pathValue)), + () => window.showErrorMessage(localize('updateTsdkFailed', 'Could not update the \'typescript.tsdk\' workspace setting. Please check that the workspace settings file is valid'))); showVersionStatusItem = true; return localModulePath; case MessageAction.useBundled: - tsConfig.update(checkWorkspaceVersionKey, false, false); - window.showInformationMessage(localize('updateLocalWorkspaceCheck', 'Updated workspace setting \'typescript.check.workspaceVersion\' to false')); + tsConfig.update(checkWorkspaceVersionKey, false, false).then( + () => window.showInformationMessage(localize('updateLocalWorkspaceCheck', 'Updated workspace setting \'typescript.check.workspaceVersion\' to false')), + () => window.showErrorMessage(localize('updateLocalWorkspaceCheckFailed', 'Could not update the \'typescript.check.workspaceVersion\' workspace setting. Please check that the workspace settings file is valid'))); return modulePath; case MessageAction.neverCheckLocalVersion: - window.showInformationMessage(localize('updateGlobalWorkspaceCheck', 'Updated user setting \'typescript.check.workspaceVersion\' to false')); - tsConfig.update(checkWorkspaceVersionKey, false, true); + tsConfig.update(checkWorkspaceVersionKey, false, true).then( + () => window.showInformationMessage(localize('updateGlobalWorkspaceCheck', 'Updated user setting \'typescript.check.workspaceVersion\' to false')), + () => window.showErrorMessage(localize('updateGlobalWorkspaceCheckFailed', 'Could not update \'typescript.check.workspaceVersion\' user setting. Please check that your user settings file is valid'))); return modulePath; default: return modulePath; diff --git a/package.json b/package.json index 8642c2d76e8..529cb07f99c 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "eslint": "^3.4.0", "event-stream": "^3.1.7", "express": "^4.13.1", + "flatpak-bundler": "^0.1.1", "ghooks": "1.0.3", "glob": "^5.0.13", "gulp": "^3.8.9", @@ -59,6 +60,7 @@ "gulp-cssnano": "^2.1.0", "gulp-filter": "^3.0.0", "gulp-flatmap": "^1.0.0", + "gulp-image-resize": "^0.10.0", "gulp-json-editor": "^2.2.1", "gulp-mocha": "^2.1.3", "gulp-remote-src": "^0.4.0", @@ -71,8 +73,6 @@ "gulp-uglify": "^2.0.0", "gulp-util": "^3.0.6", "gulp-vinyl-zip": "^1.2.2", - "gulp-image-resize": "^0.10.0", - "flatpak-bundler": "^0.1.1", "innosetup-compiler": "^5.5.60", "is": "^3.1.0", "istanbul": "^0.3.17", @@ -91,8 +91,8 @@ "sinon": "^1.17.2", "source-map": "^0.4.4", "tslint": "^3.3.0", - "typescript": "2.0.3", - "typescript-formatter": "3.1.0", + "typescript": "^2.1.4", + "typescript-formatter": "4.0.1", "uglify-js": "2.4.8", "underscore": "^1.8.2", "vinyl": "^0.4.5", diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index 80d41601b7b..47ed1616faa 100644 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=/usr/share/@@NAME@@/@@NAME@@ %U +Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window-if-not-first %U Icon=@@NAME@@ Type=Application StartupNotify=true diff --git a/src/main.js b/src/main.js index 289e0e4fb15..d45cc975b8d 100644 --- a/src/main.js +++ b/src/main.js @@ -180,6 +180,7 @@ var nodeCachedDataDir = getNodeCachedDataDir().then(function (value) { // Load our code once ready app.once('ready', function () { + global.perfAppReady = Date.now(); var nlsConfig = getNLSConfiguration(); process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); diff --git a/src/vs/base/browser/ui/sash/sash.css b/src/vs/base/browser/ui/sash/sash.css index 5a2687d5055..0c733246563 100644 --- a/src/vs/base/browser/ui/sash/sash.css +++ b/src/vs/base/browser/ui/sash/sash.css @@ -25,22 +25,22 @@ cursor: default !important; } -.vertical-cursor-container * { +.vertical-cursor-container { cursor: ew-resize; } -.horizontal-cursor-container * { +.horizontal-cursor-container { cursor: ns-resize; } /** Custom Mac Cursor */ .monaco-sash.mac.vertical, -.vertical-cursor-container-mac * { +.vertical-cursor-container-mac { cursor: col-resize; } .monaco-sash.mac.horizontal, -.horizontal-cursor-container-mac * { +.horizontal-cursor-container-mac { cursor: row-resize; } \ No newline at end of file diff --git a/src/vs/base/browser/ui/timer/timer.css b/src/vs/base/browser/ui/timer/timer.css deleted file mode 100644 index 9f3515b0d95..00000000000 --- a/src/vs/base/browser/ui/timer/timer.css +++ /dev/null @@ -1,29 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -.benchmarktimerbox { - z-index: 100; - position: absolute; - color: black; - background: lightblue; - top: 100px; - right: 20px; - font-family: monospace; -} - -.benchmarktimerbox .inner { - width: 600px; - height: 300px; - overflow: scroll; -} - -.benchmarktimerbox .timeFilter { - width: 50px; -} - -.benchmarktimerbox pre { - margin: 0; -} - -.timer-event-1 { background: rgba(190, 191, 193, 0.4); color: black; } \ No newline at end of file diff --git a/src/vs/base/browser/ui/timer/timer.ts b/src/vs/base/browser/ui/timer/timer.ts deleted file mode 100644 index 1b19e91e145..00000000000 --- a/src/vs/base/browser/ui/timer/timer.ts +++ /dev/null @@ -1,281 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import 'vs/css!./timer'; -import { TimeKeeper, ITimerEvent, getTimeKeeper } from 'vs/base/common/timer'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import DomUtils = require('vs/base/browser/dom'); - -export class TimeKeeperRenderer { - - private listenersToRemove: IDisposable[]; - private timeKeeper: TimeKeeper; - private outerDomNode: HTMLElement; - private domNode: HTMLElement; - private renderCnt: number; - private lastEventIndex: number; - - private textFilter: string; - private textFilterDomNode: HTMLInputElement; - private timeFilter: number; - private timeFilterDomNode: HTMLInputElement; - private intervalTokenId: number; - - private renderedEvents: { - [key: string]: ITimerEvent; - }; - - private onHide: () => void; - - constructor(onHide: () => void) { - this.timeKeeper = getTimeKeeper(); - this.onHide = onHide; - this.lastEventIndex = 0; - this.renderedEvents = {}; - this.renderCnt = 0; - this.listenersToRemove = []; - this.domNode = this._createDomNode(); - this.intervalTokenId = window.setInterval(() => this._render(), 500); - } - - public destroy(): void { - document.body.removeChild(this.outerDomNode); - window.clearInterval(this.intervalTokenId); - this.listenersToRemove = dispose(this.listenersToRemove); - } - - private _createDomNode(): HTMLElement { - this.outerDomNode = document.createElement('div'); - this.outerDomNode.className = 'benchmarktimerbox'; - - // Clear - let cancel: HTMLInputElement = document.createElement('input'); - cancel.type = 'button'; - cancel.value = 'Clear'; - this.listenersToRemove.push(DomUtils.addDisposableListener(cancel, 'click', () => this._onClear())); - this.outerDomNode.appendChild(cancel); - - // Text filter - this.textFilterDomNode = document.createElement('input'); - this.textFilterDomNode.type = 'text'; - this.textFilterDomNode.className = 'textFilter'; - this.listenersToRemove.push(DomUtils.addDisposableListener(this.textFilterDomNode, 'keydown', () => this.onTextFilterChange())); - this.textFilter = ''; - this.outerDomNode.appendChild(document.createTextNode('Filter')); - this.outerDomNode.appendChild(this.textFilterDomNode); - - // Time filter - this.timeFilterDomNode = document.createElement('input'); - this.timeFilterDomNode.type = 'text'; - this.timeFilterDomNode.value = '0'; - this.timeFilterDomNode.className = 'timeFilter'; - this.listenersToRemove.push(DomUtils.addDisposableListener(this.timeFilterDomNode, 'keydown', () => this.onTimeFilterChange())); - this.timeFilter = 0; - this.outerDomNode.appendChild(document.createTextNode('Hide time under')); - this.outerDomNode.appendChild(this.timeFilterDomNode); - - let hide: HTMLInputElement = document.createElement('input'); - hide.type = 'button'; - hide.value = 'Close'; - this.listenersToRemove.push(DomUtils.addDisposableListener(hide, 'click', () => { - this.onHide(); - })); - this.outerDomNode.appendChild(hide); - - let heading = document.createElement('pre'); - heading.appendChild(document.createTextNode(this.renderRow('TOPIC', 'NAME', 'TOOK', 'START', 'END'))); - this.outerDomNode.appendChild(heading); - this.outerDomNode.appendChild(document.createElement('hr')); - - let domNode = document.createElement('div'); - domNode.className = 'inner'; - this.outerDomNode.appendChild(domNode); - - document.body.appendChild(this.outerDomNode); - - return domNode; - } - - private onTextFilterChange(): void { - setTimeout(() => { - this.refilter(); - }); - } - - private onTimeFilterChange(): void { - setTimeout(() => { - this.refilter(); - }); - } - - private matchesTextFilter(event: ITimerEvent): boolean { - if (!this.textFilter) { - return true; - } - if (event.topic.toLowerCase().indexOf(this.textFilter.toLowerCase()) >= 0) { - return true; - } - if (event.name.toLowerCase().indexOf(this.textFilter.toLowerCase()) >= 0) { - return true; - } - return false; - } - - private matchesTimeFilter(event: ITimerEvent): boolean { - if (!this.timeFilter) { - return true; - } - if (event.timeTaken() >= this.timeFilter) { - return true; - } - return false; - } - - private shouldShow(event: ITimerEvent): boolean { - return this.matchesTextFilter(event) && this.matchesTimeFilter(event); - } - - private refilter(): void { - this.textFilter = this.textFilterDomNode.value; - this.timeFilter = parseInt(this.timeFilterDomNode.value, 10); - - let domNodes = Array.prototype.slice.call(this.domNode.children, 0); - for (let i = 0; i < domNodes.length; i++) { - let eventId = domNodes[i].getAttribute('data-event-id'); - let event = this.renderedEvents[eventId]; - - if (this.shouldShow(event)) { - domNodes[i].style.display = 'inherit'; - } else { - domNodes[i].style.display = 'none'; - } - } - } - - private _onClear(): void { - this.lastEventIndex = this.timeKeeper.getCollectedEvents().length; - this.renderedEvents = {}; - this.renderCnt = 0; - DomUtils.clearNode(this.domNode); - } - - private leftPaddedString(size: number, padChar: string, str: string): string { - let spaces = this._repeatStr(padChar, Math.max(0, size - str.length)); - return spaces + str; - } - - private rightPaddedString(size: number, padChar: string, str: string): string { - let spaces = this._repeatStr(padChar, Math.max(0, size - str.length)); - return str + spaces; - } - - private renderRow(topic: string, name: string, timeTook: string, timeStart: string, timerEnd: string): string { - let result = ' '; - result += this.rightPaddedString(10, ' ', topic); - result += this.rightPaddedString(30, ' ', name); - result += ' ' + this.leftPaddedString(15, ' ', timeTook); - result += ' ' + this.leftPaddedString(13, ' ', timeStart); - return result; - } - - private _suffix0(s: string): string { - if (s.charAt(s.length - 3) === '.') { - return s; - } - if (s.charAt(s.length - 2) === '.') { - return s + '0'; - } - return s + '.00'; - } - - private _twoPrecision(a: number): string { - return this._suffix0(Math.round(a * 100) / 100 + ''); - } - - private _absoluteTime(t: number): string { - if (t < 1000) { - return this._twoPrecision(t) + ' ms'; - } - t /= 1000; - if (t < 60) { - return this._twoPrecision(t) + ' s'; - } - t /= 60; - if (t < 60) { - return this._twoPrecision(t) + ' m'; - } - t /= 60; - return this._twoPrecision(t) + ' h'; - } - - private _renderEvent(domNode: HTMLElement, event: ITimerEvent): void { - let start = event.startTime.getTime() - TimeKeeper.PARSE_TIME.getTime(); - - let result = this.renderRow( - event.topic, - event.name, - this._twoPrecision(event.timeTaken()), - this._absoluteTime(start) + '', - this._absoluteTime(start + event.timeTaken()) - ); - domNode.textContent = ''; - domNode.appendChild(document.createTextNode(result)); - } - - private _renderStartTimerEvent(event: ITimerEvent): void { - let domNode = document.createElement('pre'); - this._renderEvent(domNode, event); - this.domNode.appendChild(domNode); - let idString = event.id.toString(); - - domNode.setAttribute('data-event-id', idString); - domNode.className = 'timer-event-' + (event.id % 2); - this.renderedEvents[idString] = event; - - if (this.shouldShow(this.renderedEvents[idString])) { - domNode.style.display = 'inherit'; - } else { - domNode.style.display = 'none'; - } - - this.renderCnt++; - } - - private _render(): void { - let allEvents = this.timeKeeper.getCollectedEvents(), didSomething = false; - - for (let i = this.lastEventIndex; i < allEvents.length; i++) { - let ev = allEvents[i]; - - if (!ev.stopTime) { - // This event is not yet finished => block - this.lastEventIndex = i; - if (didSomething) { - this.domNode.scrollTop = 100000; - } - return; - } - - this._renderStartTimerEvent(ev); - didSomething = true; - } - - if (didSomething) { - this.domNode.scrollTop = 100000; - } - this.lastEventIndex = allEvents.length; - } - - private _repeatStr(str: string, cnt: number): string { - let r = ''; - for (let i = 0; i < cnt; i++) { - r += str; - } - return r; - } -} - diff --git a/src/vs/base/common/timer.ts b/src/vs/base/common/timer.ts deleted file mode 100644 index 59e00729368..00000000000 --- a/src/vs/base/common/timer.ts +++ /dev/null @@ -1,293 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import Platform = require('vs/base/common/platform'); -import errors = require('vs/base/common/errors'); -import precision = require('vs/base/common/stopwatch'); -import { IDisposable } from 'vs/base/common/lifecycle'; - -export var ENABLE_TIMER = false; -var msWriteProfilerMark = Platform.globals['msWriteProfilerMark']; - -export enum Topic { - EDITOR, - LANGUAGES, - WORKER, - WORKBENCH, - STARTUP -} - -export interface ITimerEvent { - id: number; - topic: string; - name: string; - description: string; - data: any; - - startTime: Date; - stopTime: Date; - - stop(stopTime?: Date): void; - timeTaken(): number; -} - -export interface IExistingTimerEvent { - topic: string; - name: string; - - description?: string; - - startTime: Date; - stopTime: Date; -} - -class NullTimerEvent implements ITimerEvent { - public id: number; - public topic: string; - public name: string; - public description: string; - public data: any; - - public startTime: Date; - public stopTime: Date; - - public stop(): void { - return; - } - - public timeTaken(): number { - return -1; - } -} - -class TimerEvent implements ITimerEvent { - public id: number; - public topic: string; - public name: string; - public description: string; - public data: any; - - public startTime: Date; - public stopTime: Date; - - private timeKeeper: TimeKeeper; - private sw: precision.StopWatch; - - constructor(timeKeeper: TimeKeeper, name: string, topic: string, startTime?: Date, description?: string) { - this.timeKeeper = timeKeeper; - this.name = name; - this.description = description; - this.topic = topic; - this.stopTime = null; - - if (startTime) { - this.startTime = startTime; - return; - } - - this.startTime = new Date(); - this.sw = precision.StopWatch.create(); - - if (msWriteProfilerMark) { - var profilerName = ['Monaco', this.topic, this.name, 'start']; - msWriteProfilerMark(profilerName.join('|')); - } - } - - public stop(stopTime?: Date): void { - - // already stopped - if (this.stopTime !== null) { - return; - } - - if (stopTime) { - this.stopTime = stopTime; - this.sw = null; - this.timeKeeper._onEventStopped(this); - return; - } - - this.stopTime = new Date(); - if (this.sw) { - this.sw.stop(); - } - - this.timeKeeper._onEventStopped(this); - - if (msWriteProfilerMark) { - var profilerName = ['Monaco', this.topic, this.name, 'stop']; - msWriteProfilerMark(profilerName.join('|')); - } - } - - public timeTaken(): number { - if (this.sw) { - return this.sw.elapsed(); - } - if (this.stopTime) { - return this.stopTime.getTime() - this.startTime.getTime(); - } - return -1; - } -} - -export interface IEventsListener { - (events: ITimerEvent[]): void; -} - -export class TimeKeeper { - /** - * After being started for 1 minute, all timers are automatically stopped. - */ - private static _MAX_TIMER_LENGTH = 60000; // 1 minute - /** - * Every 2 minutes, a sweep of current started timers is done. - */ - private static _CLEAN_UP_INTERVAL = 120000; // 2 minutes - /** - * Collect at most 1000 events. - */ - private static _EVENT_CACHE_LIMIT = 1000; - - private static EVENT_ID = 1; - public static PARSE_TIME = new Date(); - - - private cleaningIntervalId: Platform.IntervalToken; - private collectedEvents: ITimerEvent[]; - private listeners: IEventsListener[]; - - constructor() { - this.cleaningIntervalId = -1; - this.collectedEvents = []; - this.listeners = []; - } - - public isEnabled(): boolean { - return ENABLE_TIMER; - } - - public start(topic: Topic | string, name: string, start?: Date, description?: string): ITimerEvent { - if (!this.isEnabled()) { - return nullEvent; - } - - var strTopic: string; - - if (typeof topic === 'string') { - strTopic = topic; - } else if (topic === Topic.EDITOR) { - strTopic = 'Editor'; - } else if (topic === Topic.LANGUAGES) { - strTopic = 'Languages'; - } else if (topic === Topic.WORKER) { - strTopic = 'Worker'; - } else if (topic === Topic.WORKBENCH) { - strTopic = 'Workbench'; - } else if (topic === Topic.STARTUP) { - strTopic = 'Startup'; - } - - this.initAutoCleaning(); - var event = new TimerEvent(this, name, strTopic, start, description); - this.addEvent(event); - - return event; - } - - public dispose(): void { - if (this.cleaningIntervalId !== -1) { - Platform.clearInterval(this.cleaningIntervalId); - this.cleaningIntervalId = -1; - } - } - - public addListener(listener: IEventsListener): IDisposable { - this.listeners.push(listener); - return { - dispose: () => { - for (var i = 0; i < this.listeners.length; i++) { - if (this.listeners[i] === listener) { - this.listeners.splice(i, 1); - return; - } - } - } - }; - } - - private addEvent(event: ITimerEvent): void { - event.id = TimeKeeper.EVENT_ID; - TimeKeeper.EVENT_ID++; - this.collectedEvents.push(event); - // expire items from the front of the cache - if (this.collectedEvents.length > TimeKeeper._EVENT_CACHE_LIMIT) { - this.collectedEvents.shift(); - } - } - - private initAutoCleaning(): void { - if (this.cleaningIntervalId === -1) { - this.cleaningIntervalId = Platform.setInterval(() => { - var now = Date.now(); - this.collectedEvents.forEach((event) => { - if (!event.stopTime && (now - event.startTime.getTime()) >= TimeKeeper._MAX_TIMER_LENGTH) { - event.stop(); - } - }); - }, TimeKeeper._CLEAN_UP_INTERVAL); - } - } - - public getCollectedEvents(): ITimerEvent[] { - return this.collectedEvents.slice(0); - } - - public clearCollectedEvents(): void { - this.collectedEvents = []; - } - - _onEventStopped(event: ITimerEvent): void { - var emitEvents = [event]; - - var listeners = this.listeners.slice(0); - for (var i = 0; i < listeners.length; i++) { - try { - listeners[i](emitEvents); - } catch (e) { - errors.onUnexpectedError(e); - } - } - } - - public setInitialCollectedEvents(events: IExistingTimerEvent[], startTime?: Date): void { - if (!this.isEnabled()) { - return; - } - - if (startTime) { - TimeKeeper.PARSE_TIME = startTime; - } - - events.forEach((event) => { - var e = new TimerEvent(this, event.name, event.topic, event.startTime, event.description); - e.stop(event.stopTime); - this.addEvent(e); - }); - } -} - -var timeKeeper = new TimeKeeper(); -export var nullEvent: ITimerEvent = new NullTimerEvent(); - -export function start(topic: Topic | string, name: string, start?: Date, description?: string): ITimerEvent { - return timeKeeper.start(topic, name, start, description); -} - -export function getTimeKeeper(): TimeKeeper { - return timeKeeper; -} diff --git a/src/vs/base/parts/tree/browser/treeImpl.ts b/src/vs/base/parts/tree/browser/treeImpl.ts index d7453bc6b7b..fe1198623fe 100644 --- a/src/vs/base/parts/tree/browser/treeImpl.ts +++ b/src/vs/base/parts/tree/browser/treeImpl.ts @@ -133,7 +133,7 @@ export class Tree extends Events.EventEmitter implements _.ITree { } public collapse(element: any, recursive: boolean = false): WinJS.Promise { - return this.model.collapse(element); + return this.model.collapse(element, recursive); } public collapseAll(elements: any[] = null, recursive: boolean = false): WinJS.Promise { diff --git a/src/vs/base/test/common/utils.ts b/src/vs/base/test/common/utils.ts index f8693d9cd69..f69d864e509 100644 --- a/src/vs/base/test/common/utils.ts +++ b/src/vs/base/test/common/utils.ts @@ -13,18 +13,21 @@ import URI from 'vs/base/common/uri'; export class DeferredTPromise extends TPromise { - public canceled = false; + public canceled: boolean; private completeCallback: TValueCallback; private errorCallback: (err: any) => void; private progressCallback: ProgressCallback; constructor() { + let captured: any; super((c, e, p) => { - this.completeCallback = c; - this.errorCallback = e; - this.progressCallback = p; + captured = { c, e, p }; }, () => this.oncancel()); + this.canceled = false; + this.completeCallback = captured.c; + this.errorCallback = captured.e; + this.progressCallback = captured.p; } public complete(value: T) { @@ -51,7 +54,13 @@ export class DeferredPPromise extends PPromise { private progressCallback: TProgressCallback

; constructor(init: (complete: TValueCallback, error: (err: any) => void, progress: TProgressCallback

) => void = (c, e, p) => { }, oncancel?: any) { - super((c, e, p) => { this.completeCallback = c; this.errorCallback = e; this.progressCallback = p; }, oncancel ? oncancel : () => this.oncancel); + let captured: any; + super((c, e, p) => { + captured = { c, e, p }; + }, oncancel ? oncancel : () => this.oncancel); + this.completeCallback = captured.c; + this.errorCallback = captured.e; + this.progressCallback = captured.p; } private oncancel(): void { diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index 026fad8e55b..e413e7775bf 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -93,7 +93,7 @@ export class LaunchService implements ILaunchService { let usedWindows: VSCodeWindow[]; if (!!args.extensionDevelopmentPath) { this.windowsService.openExtensionDevelopmentHostWindow({ context, cli: args, userEnv }); - } else if (args._.length === 0 && args['new-window']) { + } else if (args._.length === 0 && args['new-window'] || args['new-window-if-not-first']) { usedWindows = this.windowsService.open({ context, cli: args, userEnv, forceNewWindow: true, forceEmpty: true }); } else if (args._.length === 0) { usedWindows = [this.windowsService.focusLastActive(args, context)]; @@ -102,7 +102,7 @@ export class LaunchService implements ILaunchService { context, cli: args, userEnv, - forceNewWindow: args.wait || args['new-window'], + forceNewWindow: args.wait || args['new-window'] || args['new-window-if-not-first'], preferNewWindow: !args['reuse-window'], forceReuseWindow: args['reuse-window'], diffMode: args.diff diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index b9e11a0702a..5eb0da6e884 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -257,7 +257,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo } else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) { windowsMainService.open({ context: OpenContext.DOCK, cli: environmentService.args, pathsToOpen: global.macOpenFiles, initialStartup: true }); // mac: open-file event received on startup } else { - windowsMainService.open({ context, cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff, initialStartup: true }); // default: read paths from cli + windowsMainService.open({ context, cli: environmentService.args, forceNewWindow: environmentService.args['new-window'] || environmentService.args['new-window-if-not-first'], diffMode: environmentService.args.diff, initialStartup: true }); // default: read paths from cli } // Install Menu diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 56536188d21..dd967a6e14c 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -82,6 +82,7 @@ export interface IWindowConfiguration extends ParsedArgs { isInitialStartup?: boolean; perfStartTime?: number; + perfAppReady?: number; perfWindowLoadTime?: number; workspacePath?: string; @@ -487,6 +488,7 @@ export class VSCodeWindow implements IVSCodeWindow { // Perf Counters windowConfiguration.perfStartTime = global.perfStartTime; + windowConfiguration.perfAppReady = global.perfAppReady; windowConfiguration.perfWindowLoadTime = Date.now(); // Config (combination of process.argv and window configuration) diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index 26cdc0c5193..34a5c02a2fe 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -41,41 +41,6 @@ class CSSBasedConfigurationCache { } } -class CharWidthReader { - - private _chr: string; - private _width: number; - - public get width(): number { return this._width; } - - constructor(chr: string) { - this._chr = chr; - this._width = 0; - } - - public render(out: HTMLSpanElement): void { - if (this._chr === ' ') { - let htmlString = ' '; - // Repeat character 256 (2^8) times - for (let i = 0; i < 8; i++) { - htmlString += htmlString; - } - out.innerHTML = htmlString; - } else { - let testString = this._chr; - // Repeat character 256 (2^8) times - for (let i = 0; i < 8; i++) { - testString += testString; - } - out.textContent = testString; - } - } - - public read(out: HTMLSpanElement): void { - this._width = out.offsetWidth / 256; - } -} - class CSSBasedConfiguration extends Disposable { public static INSTANCE = new CSSBasedConfiguration(); @@ -154,59 +119,15 @@ class CSSBasedConfiguration extends Disposable { } } - private static _testElementId(index: number): string { - return 'editorSizeProvider' + index; - } - - private static _createTestElements(bareFontInfo: BareFontInfo, readers: CharWidthReader[]): HTMLElement { - let container = document.createElement('div'); - Configuration.applyFontInfoSlow(container, bareFontInfo); - container.style.position = 'absolute'; - container.style.top = '-50000px'; - container.style.width = '50000px'; - - for (let i = 0, len = readers.length; i < len; i++) { - container.appendChild(document.createElement('br')); - - let testElement = document.createElement('span'); - testElement.id = this._testElementId(i); - readers[i].render(testElement); - - container.appendChild(testElement); - } - - container.appendChild(document.createElement('br')); - - return container; - } - - private static _readFromTestElements(readers: CharWidthReader[]): void { - for (let i = 0, len = readers.length; i < len; i++) { - readers[i].read(document.getElementById(this._testElementId(i))); - } - } - - private static _runReaders(bareFontInfo: BareFontInfo, readers: CharWidthReader[]): void { - // Create a test container with all these test elements - let testContainer = this._createTestElements(bareFontInfo, readers); - - // Add the container to the DOM - document.body.appendChild(testContainer); - - // Read various properties - this._readFromTestElements(readers); - - // Remove the container from the DOM - document.body.removeChild(testContainer); - } - private static _actualReadConfiguration(bareFontInfo: BareFontInfo): FontInfo { - let typicalHalfwidthCharacter = new CharWidthReader('n'); - let typicalFullwidthCharacter = new CharWidthReader('\uff4d'); - let space = new CharWidthReader(' '); - let digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].map(chr => new CharWidthReader(chr)); + let canvasElem = document.createElement('canvas'); + let context = canvasElem.getContext('2d'); + context.font = `normal normal normal normal ${bareFontInfo.fontSize}px / ${bareFontInfo.lineHeight}px ${bareFontInfo.fontFamily}`; - this._runReaders(bareFontInfo, digits.concat([typicalHalfwidthCharacter, typicalFullwidthCharacter, space])); + let typicalHalfwidthCharacter = context.measureText('n'); + let typicalFullwidthCharacter = context.measureText('\uff4d'); + let space = context.measureText(' '); + let digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].map(chr => context.measureText(chr)); let maxDigitWidth = 0; for (let i = 0, len = digits.length; i < len; i++) { diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index b38afa64ef0..4633a53a146 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -7,7 +7,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { EmitterEvent, IEventEmitter } from 'vs/base/common/eventEmitter'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import * as timer from 'vs/base/common/timer'; import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { StyleMutator } from 'vs/base/browser/styleMutator'; @@ -900,14 +899,12 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp if (!dom.isInDOM(this.domNode)) { return; } - let t = timer.start(timer.Topic.EDITOR, 'View.render'); let viewPartsToRender = this._getViewPartsToRender(); if (!this.viewLines.shouldRender() && viewPartsToRender.length === 0) { // Nothing to render this.keyboardHandler.writeToTextArea(); - t.stop(); return; } @@ -941,8 +938,6 @@ export class View extends ViewEventHandler implements editorBrowser.IView, IDisp // Render the scrollbar this.layoutProvider.renderScrollbar(); - - t.stop(); } private _setHasFocus(newHasFocus: boolean): void { diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 11f9a39f1b1..dfd9904fa86 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -598,50 +598,8 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed protected abstract readConfiguration(styling: editorCommon.BareFontInfo): editorCommon.FontInfo; } -/** - * Helper to update Monaco Editor Settings from configurations service. - */ -export class EditorConfiguration { - public static EDITOR_SECTION = 'editor'; - public static DIFF_EDITOR_SECTION = 'diffEditor'; - - /** - * Ask the provided configuration service to apply its configuration to the provided editor. - */ - public static apply(config: any, editor: editorCommon.IEditor): void { - if (!config) { - return; - } - - // Editor Settings (Code Editor, Diff, Terminal) - if (editor && typeof editor.updateOptions === 'function') { - let type = editor.getEditorType(); - if (type !== editorCommon.EditorType.ICodeEditor && type !== editorCommon.EditorType.IDiffEditor) { - return; - } - - let editorConfig = config[EditorConfiguration.EDITOR_SECTION]; - if (type === editorCommon.EditorType.IDiffEditor) { - let diffEditorConfig = config[EditorConfiguration.DIFF_EDITOR_SECTION]; - if (diffEditorConfig) { - if (!editorConfig) { - editorConfig = diffEditorConfig; - } else { - editorConfig = objects.mixin(editorConfig, diffEditorConfig); - } - } - } - - if (editorConfig) { - delete editorConfig.readOnly; // Prevent someone from making editor readonly - editor.updateOptions(editorConfig); - } - } - } -} - -let configurationRegistry = Registry.as(Extensions.Configuration); -let editorConfiguration: IConfigurationNode = { +const configurationRegistry = Registry.as(Extensions.Configuration); +const editorConfiguration: IConfigurationNode = { 'id': 'editor', 'order': 5, 'type': 'object', diff --git a/src/vs/editor/common/model/textModelWithTokens.ts b/src/vs/editor/common/model/textModelWithTokens.ts index 2479672941d..8b10f46c66c 100644 --- a/src/vs/editor/common/model/textModelWithTokens.ts +++ b/src/vs/editor/common/model/textModelWithTokens.ts @@ -8,7 +8,6 @@ import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable } from 'vs/base/common/lifecycle'; import { StopWatch } from 'vs/base/common/stopwatch'; -import * as timer from 'vs/base/common/timer'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { TextModel } from 'vs/editor/common/model/textModel'; @@ -274,7 +273,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke this._withModelTokensChangedEventBuilder((eventBuilder) => { - var t1 = timer.start(timer.Topic.EDITOR, 'backgroundTokenization'); toLineNumber = Math.min(this._lines.length, toLineNumber); var MAX_ALLOWED_TIME = 20, @@ -322,8 +320,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke if (this._invalidLineStartIndex < this._lines.length) { this._beginBackgroundTokenization(); } - - t1.stop(); }); } diff --git a/src/vs/editor/common/modes/linkComputer.ts b/src/vs/editor/common/modes/linkComputer.ts index ce1c82562ac..24b52884752 100644 --- a/src/vs/editor/common/modes/linkComputer.ts +++ b/src/vs/editor/common/modes/linkComputer.ts @@ -125,7 +125,7 @@ const enum CharacterClass { } const classifier = (function () { - let result = new CharacterClassifier(CharacterClass.None); + let result = new CharacterClassifier(CharacterClass.None); const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;?!@#$%&*‘“〈《「『【〔([{「」}])〕】』」》〉”’`~…'; for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) { diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts index 979421d8f9d..10e0304f3a2 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts @@ -76,7 +76,7 @@ export class DefinitionAction extends EditorAction { let result: Location[] = []; for (let i = 0; i < references.length; i++) { let reference = references[i]; - if (!reference) { + if (!reference || !reference.range) { continue; } let {uri, range} = reference; @@ -110,7 +110,7 @@ export class DefinitionAction extends EditorAction { } else { let next = model.nearestReference(editor.getModel().uri, editor.getPosition()); this._openReference(editorService, next, this._configuration.openToSide).then(editor => { - if (model.references.length > 1) { + if (editor && model.references.length > 1) { this._openInPeek(editorService, editor, model); } else { model.dispose(); @@ -128,7 +128,7 @@ export class DefinitionAction extends EditorAction { revealIfVisible: !sideBySide } }, sideBySide).then(editor => { - return editor.getControl(); + return editor && editor.getControl(); }); } diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index d789272604a..ea5a3ee80fe 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -9,6 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { IEditorViewState } from 'vs/editor/common/editorCommon'; export const IEditorService = createDecorator('editorService'); @@ -238,6 +239,11 @@ export interface ITextEditorOptions extends IEditorOptions { endColumn?: number; }; + /** + * Text editor view state. + */ + viewState?: IEditorViewState; + /** * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport. */ diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index a95ec8f2bea..36ecf5f1fb6 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -14,6 +14,7 @@ export interface ParsedArgs { diff?: boolean; goto?: boolean; 'new-window'?: boolean; + 'new-window-if-not-first'?: boolean; 'reuse-window'?: boolean; locale?: string; 'user-data-dir'?: string; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index caa91b82bb4..c6f6cc136c5 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -30,6 +30,7 @@ const options: minimist.Opts = { 'diff', 'goto', 'new-window', + 'new-window-if-not-first', 'reuse-window', 'performance', 'verbose', diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index e3e072b288e..37f5a52df21 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -223,7 +223,7 @@ export class FileChangesEvent extends events.Event { return false; } - return this._changes.some((change) => { + return this._changes.some(change => { if (change.type !== type) { return false; } @@ -280,11 +280,11 @@ export class FileChangesEvent extends events.Event { } private getOfType(type: FileChangeType): IFileChange[] { - return this._changes.filter((change) => change.type === type); + return this._changes.filter(change => change.type === type); } private hasType(type: FileChangeType): boolean { - return this._changes.some((change) => { + return this._changes.some(change => { return change.type === type; }); } diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index f4fb6eb0dfb..27ffed19554 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -123,13 +123,15 @@ export class InstantiationService implements IInstantiationService { // arguments defined by service decorators let serviceDependencies = _util.getServiceDependencies(desc.ctor).sort((a, b) => a.index - b.index); - let serviceArgs = serviceDependencies.map(dependency => { + let serviceArgs: any[] = []; + for (const dependency of serviceDependencies) { let service = this._getOrCreateServiceInstance(dependency.id); if (!service && this._strict && !dependency.optional) { throw new Error(`[createInstance] ${desc.ctor.name} depends on UNKNOWN service ${dependency.id}.`); } - return service; - }); + serviceArgs.push(service); + } + let firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : staticArgs.length; // check for argument mismatches, adjust static args if needed diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 1f8e2e1796a..4f26af718d2 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -110,7 +110,7 @@ export class ResourceLabel extends IconLabel { const resource = this.label.resource; let title = ''; - if (this.options && this.options.title) { + if (this.options && typeof this.options.title === 'string') { title = this.options.title; } else if (resource) { title = getPathLabel(resource.fsPath); diff --git a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts index ce92c4c1a14..ebf4a30612c 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupsControl.ts @@ -758,7 +758,7 @@ export class EditorGroupsControl implements IEditorGroupsControl, IVerticalSashL this.sashTwo.setOrientation(this.layoutVertically ? Orientation.VERTICAL : Orientation.HORIZONTAL); // Trigger layout - this.arrangeGroups(GroupArrangement.EVEN); + this.arrangeGroups(); } } @@ -766,7 +766,7 @@ export class EditorGroupsControl implements IEditorGroupsControl, IVerticalSashL return this.layoutVertically ? 'vertical' : 'horizontal'; } - public arrangeGroups(arrangement: GroupArrangement): void { + public arrangeGroups(arrangement?: GroupArrangement): void { if (!this.dimension) { return; // too early } @@ -778,27 +778,49 @@ export class EditorGroupsControl implements IEditorGroupsControl, IVerticalSashL return; // need more editors } - // Minimize Others - if (arrangement === GroupArrangement.MINIMIZE_OTHERS) { - POSITIONS.forEach(position => { - if (this.visibleEditors[position]) { - if (position !== this.lastActivePosition) { - this.silosSize[position] = this.minSize; - availableSize -= this.minSize; + switch (arrangement) { + case GroupArrangement.MINIMIZE_OTHERS: + // Minimize Others + POSITIONS.forEach(position => { + if (this.visibleEditors[position]) { + if (position !== this.lastActivePosition) { + this.silosSize[position] = this.minSize; + availableSize -= this.minSize; + } } - } - }); + }); - this.silosSize[this.lastActivePosition] = availableSize; - } + this.silosSize[this.lastActivePosition] = availableSize; + break; + case GroupArrangement.EVEN: + // Even Sizes + POSITIONS.forEach(position => { + if (this.visibleEditors[position]) { + this.silosSize[position] = availableSize / visibleEditors; + } + }); + break; + default: + // Minimized editors should remain minimized, others should keep their relative Sizes + let oldNonMinimizedTotal = 0; + POSITIONS.forEach(position => { + if (this.visibleEditors[position]) { + if (this.silosMinimized[position]) { + this.silosSize[position] = this.minSize; + availableSize -= this.minSize; + } else { + oldNonMinimizedTotal += this.silosSize[position]; + } + } + }); - // Even Sizes - else if (arrangement === GroupArrangement.EVEN) { - POSITIONS.forEach(position => { - if (this.visibleEditors[position]) { - this.silosSize[position] = availableSize / visibleEditors; - } - }); + // Set size for non-minimized editors + const scaleFactor = availableSize / oldNonMinimizedTotal; + POSITIONS.forEach(position => { + if (this.visibleEditors[position] && !this.silosMinimized[position]) { + this.silosSize[position] *= scaleFactor; + } + }); } // Since we triggered a change in minimized/maximized editors, we need diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index d9747208de9..18a16159854 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -9,13 +9,12 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder } from 'vs/base/browser/builder'; import objects = require('vs/base/common/objects'); import errors = require('vs/base/common/errors'); +import types = require('vs/base/common/types'); import DOM = require('vs/base/browser/dom'); import { CodeEditor } from 'vs/editor/browser/codeEditor'; import { EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { EditorConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorViewState, IEditor, IEditorOptions, EventType as EditorEventType } from 'vs/editor/common/editorCommon'; -import { IFilesConfiguration } from 'vs/platform/files/common/files'; +import { IEditorViewState, IEditor, IEditorOptions, EventType as EditorEventType, EditorType } from 'vs/editor/common/editorCommon'; import { Position } from 'vs/platform/editor/common/editor'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -34,6 +33,11 @@ interface ITextEditorViewState { 2?: IEditorViewState; } +interface IEditorConfiguration { + editor: any; + diffEditor: any; +} + /** * The base class of editors that leverage the text editor for the editing experience. This class is only intended to * be subclassed and not instantiated. @@ -56,14 +60,14 @@ export abstract class BaseTextEditor extends BaseEditor { super(id, telemetryService); this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.handleConfigurationChangeEvent(e.config))); - this.toUnbind.push(themeService.onDidColorThemeChange(_ => this.handleConfigurationChangeEvent())); + this.toUnbind.push(themeService.onDidColorThemeChange(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration()))); } protected get instantiationService(): IInstantiationService { return this._instantiationService; } - private handleConfigurationChangeEvent(configuration?: any): void { + private handleConfigurationChangeEvent(configuration: IEditorConfiguration): void { if (this.isVisible()) { this.applyConfiguration(configuration); } else { @@ -73,28 +77,27 @@ export abstract class BaseTextEditor extends BaseEditor { private consumePendingConfigurationChangeEvent(): void { if (this.hasPendingConfigurationChange) { - this.applyConfiguration(this.configurationService.getConfiguration()); + this.applyConfiguration(this.configurationService.getConfiguration()); this.hasPendingConfigurationChange = false; } } - protected applyConfiguration(configuration?: any): void { + private applyConfiguration(configuration: IEditorConfiguration): void { if (!this.editorControl) { return; } - // Configuration & Options - if (configuration) { - const specificEditorSettings = this.getCodeEditorOptions(); - configuration = objects.clone(configuration); // dont modify original config - objects.assign(configuration[EditorConfiguration.EDITOR_SECTION], specificEditorSettings); - EditorConfiguration.apply(configuration, this.editorControl); + // Specific editor options always overwrite user configuration + const editorConfiguration = types.isObject(configuration.editor) ? objects.clone(configuration.editor) : Object.create(null); + objects.assign(editorConfiguration, this.getCodeEditorOptions()); + + // Handle diff editor specially by merging in diffEditor configuration + if (this.editorControl.getEditorType() === EditorType.IDiffEditor && types.isObject(configuration.diffEditor)) { + objects.mixin(editorConfiguration, configuration.diffEditor); } - // Just options - else { - this.editorControl.updateOptions(this.getCodeEditorOptions()); - } + // Apply to control + this.editorControl.updateOptions(editorConfiguration); } protected getCodeEditorOptions(): IEditorOptions { @@ -119,7 +122,7 @@ export abstract class BaseTextEditor extends BaseEditor { this.toUnbind.push(DOM.addDisposableListener(window, DOM.EventType.BLUR, () => this.onWindowFocusLost())); // Configuration - this.applyConfiguration(this.configurationService.getConfiguration()); + this.applyConfiguration(this.configurationService.getConfiguration()); } private onEditorFocusLost(): void { diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 4717f2ec35c..dc18cc01c1f 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -583,7 +583,7 @@ export class TextEditorOptions extends EditorOptions { public static from(input: IBaseResourceInput): TextEditorOptions { let options: TextEditorOptions = null; if (input && input.options) { - if (input.options.selection || input.options.forceOpen || input.options.revealIfVisible || input.options.preserveFocus || input.options.pinned || input.options.inactive || typeof input.options.index === 'number') { + if (input.options.selection || input.options.viewState || input.options.forceOpen || input.options.revealIfVisible || input.options.preserveFocus || input.options.pinned || input.options.inactive || typeof input.options.index === 'number') { options = new TextEditorOptions(); } @@ -616,6 +616,10 @@ export class TextEditorOptions extends EditorOptions { options.revealInCenterIfOutsideViewport = true; } + if (input.options.viewState) { + options.editorViewState = input.options.viewState; + } + if (typeof input.options.index === 'number') { options.index = input.options.index; } diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 10f15341b35..3c1e03ac623 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -371,7 +371,8 @@ export class ShowStartupPerformance extends Action { const metrics: IStartupMetrics = this.timerService.startupMetrics; if (metrics.initialStartup) { - table.push({ Topic: '[main] start => window.loadUrl()', 'Took (ms)': metrics.timers.ellapsedWindowLoad }); + table.push({ Topic: '[main] start => app.isReady', 'Took (ms)': metrics.timers.ellapsedAppReady }); + table.push({ Topic: '[main] app.isReady => window.loadUrl()', 'Took (ms)': metrics.timers.ellapsedWindowLoad }); } table.push({ Topic: '[renderer] window.loadUrl() => begin to require(workbench.main.js)', 'Took (ms)': metrics.timers.ellapsedWindowLoadToRequire }); diff --git a/src/vs/workbench/electron-browser/bootstrap/index.js b/src/vs/workbench/electron-browser/bootstrap/index.js index b03d213e348..5d438e137a2 100644 --- a/src/vs/workbench/electron-browser/bootstrap/index.js +++ b/src/vs/workbench/electron-browser/bootstrap/index.js @@ -16,24 +16,7 @@ const ipc = electron.ipcRenderer; process.lazyEnv = new Promise(function (resolve) { - - const origEnv = process.env; - - // warn about missing environment variables - // while we are resolve lazyEnv - process.env = new Proxy(origEnv, { - get: function (target, name) { - const result = target[name]; - if (typeof result === 'undefined') { - console.warn('process.env[\'' + name + '\'] is undefined AND \'process.lazyEnv\' is NOT READY yet.'); - } - return result; - } - }); - ipc.once('vscode:acceptShellEnv', function (event, shellEnv) { - // store process.env, mixin shellEnv, done - process.env = origEnv; assign(process.env, shellEnv); resolve(process.env); }); @@ -202,6 +185,7 @@ function main() { isInitialStartup: !!configuration.isInitialStartup, hasAccessibilitySupport: !!configuration.accessibilitySupport, start: new Date(configuration.perfStartTime), + appReady: new Date(configuration.perfAppReady), windowLoad: new Date(configuration.perfWindowLoadTime), beforeLoadWorkbenchMain: new Date() }; diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index cc391d5aa7d..4f2a20f0373 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -14,7 +14,6 @@ import { domContentLoaded } from 'vs/base/browser/dom'; import errors = require('vs/base/common/errors'); import platform = require('vs/base/common/platform'); import paths = require('vs/base/common/paths'); -import timer = require('vs/base/common/timer'); import uri from 'vs/base/common/uri'; import strings = require('vs/base/common/strings'); import { IResourceInput } from 'vs/platform/editor/common/editor'; @@ -62,10 +61,6 @@ export function startup(configuration: IWindowConfiguration): TPromise { filesToDiff }; - if (configuration.performance) { - timer.ENABLE_TIMER = true; - } - // Resolve workspace return getWorkspace(configuration.workspacePath).then(workspace => { @@ -171,4 +166,4 @@ function loaderError(err: Error): Error { } return new Error(nls.localize('loaderErrorNative', "Failed to load a required file. Please restart the application to try again. Details: {0}", JSON.stringify(err))); -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index 2f2f422e136..997807ba6e9 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -717,15 +717,7 @@ export class FocusProcessAction extends AbstractDebugAction { return this.debugService.focusStackFrameAndEvaluate(null, process).then(() => { const stackFrame = this.debugService.getViewModel().focusedStackFrame; if (stackFrame) { - return this.editorService.openEditor({ - resource: stackFrame.source.uri, - options: { - preserveFocus: true, - selection: { startLineNumber: stackFrame.lineNumber, startColumn: 1 }, - revealIfVisible: true, - revealInCenterIfOutsideViewport: true - } - }); + return stackFrame.openInEditor(this.editorService, true); } }); } diff --git a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts index e74b027c188..ceb3ae21200 100644 --- a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts +++ b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as lifecycle from 'vs/base/common/lifecycle'; import uri from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import { guessMimeTypes } from 'vs/base/common/mime'; @@ -10,13 +11,15 @@ import { IModel } from 'vs/editor/common/editorCommon'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { DEBUG_SCHEME, IDebugService } from 'vs/workbench/parts/debug/common/debug'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { DEBUG_SCHEME, IDebugService, State } from 'vs/workbench/parts/debug/common/debug'; import { Model } from 'vs/workbench/parts/debug/common/debugModel'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; export class DebugContentProvider implements IWorkbenchContribution, ITextModelContentProvider { + private modelsToDispose: IModel[]; + constructor( @ITextModelResolverService textModelResolverService: ITextModelResolverService, @IDebugService private debugService: IDebugService, @@ -24,6 +27,12 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC @IModeService private modeService: IModeService ) { textModelResolverService.registerTextModelContentProvider(DEBUG_SCHEME, this); + this.modelsToDispose = []; + this.debugService.onDidChangeState(() => { + if (this.debugService.state === State.Inactive) { + this.modelsToDispose = lifecycle.dispose(this.modelsToDispose); + } + }); } public getId(): string { @@ -39,8 +48,10 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC return process.session.source({ sourceReference: Source.getSourceReference(resource) }).then(response => { const mime = response.body.mimeType || guessMimeTypes(resource.toString())[0]; const modePromise = this.modeService.getOrCreateMode(mime); + const model = this.modelService.createModel(response.body.content, modePromise, resource); + this.modelsToDispose.push(model); - return this.modelService.createModel(response.body.content, modePromise, resource); + return model; }, err => { (this.debugService.getModel()).sourceIsUnavailable(resource); return err; diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index 294dd40d0f1..7e2ace18c1f 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -18,7 +18,7 @@ interface IDebugEditorModelData { toDispose: lifecycle.IDisposable[]; breakpointDecorationIds: string[]; breakpointLines: number[]; - breakpointDecorationsAsMap: { [decorationId: string]: boolean; }; + breakpointDecorationsAsMap: Map; currentStackDecorations: string[]; topStackFrameRange: IRange; dirty: boolean; @@ -29,16 +29,14 @@ const stickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges; export class DebugEditorModelManager implements IWorkbenchContribution { static ID = 'breakpointManager'; - private modelData: { - [modelUrl: string]: IDebugEditorModelData; - }; + private modelDataMap: Map; private toDispose: lifecycle.IDisposable[]; constructor( @IModelService private modelService: IModelService, @IDebugService private debugService: IDebugService ) { - this.modelData = Object.create(null); + this.modelDataMap = new Map(); this.toDispose = []; this.registerListeners(); } @@ -48,14 +46,14 @@ export class DebugEditorModelManager implements IWorkbenchContribution { } public dispose(): void { - Object.keys(this.modelData).forEach(modelUriStr => { - lifecycle.dispose(this.modelData[modelUriStr].toDispose); - this.modelData[modelUriStr].model.deltaDecorations(this.modelData[modelUriStr].breakpointDecorationIds, []); - this.modelData[modelUriStr].model.deltaDecorations(this.modelData[modelUriStr].currentStackDecorations, []); + this.modelDataMap.forEach(modelData => { + lifecycle.dispose(modelData.toDispose); + modelData.model.deltaDecorations(modelData.breakpointDecorationIds, []); + modelData.model.deltaDecorations(modelData.currentStackDecorations, []); }); this.toDispose = lifecycle.dispose(this.toDispose); - this.modelData = null; + this.modelDataMap.clear(); } private registerListeners(): void { @@ -67,7 +65,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.onFocusStackFrame())); this.toDispose.push(this.debugService.onDidChangeState(() => { if (this.debugService.state === State.Inactive) { - Object.keys(this.modelData).forEach(key => this.modelData[key].dirty = false); + this.modelDataMap.forEach(modelData => modelData.dirty = false); } })); } @@ -80,40 +78,41 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const breakPointDecorations = model.deltaDecorations([], this.createBreakpointDecorations(breakpoints)); const toDispose: lifecycle.IDisposable[] = [model.onDidChangeDecorations((e) => this.onModelDecorationsChanged(modelUrlStr, e))]; + const breakpointDecorationsAsMap = new Map(); + breakPointDecorations.forEach(bpd => breakpointDecorationsAsMap.set(bpd, true)); - this.modelData[modelUrlStr] = { + this.modelDataMap.set(modelUrlStr, { model: model, toDispose: toDispose, breakpointDecorationIds: breakPointDecorations, breakpointLines: breakpoints.map(bp => bp.lineNumber), - breakpointDecorationsAsMap: objects.toObject(breakPointDecorations, key => key, key => true), + breakpointDecorationsAsMap, currentStackDecorations: currentStackDecorations, topStackFrameRange: null, dirty: false - }; + }); } private onModelRemoved(model: IModel): void { const modelUriStr = model.uri.toString(); - if (this.modelData[modelUriStr]) { - lifecycle.dispose(this.modelData[modelUriStr].toDispose); - delete this.modelData[modelUriStr]; + if (this.modelDataMap.has(modelUriStr)) { + lifecycle.dispose(this.modelDataMap.get(modelUriStr).toDispose); + this.modelDataMap.delete(modelUriStr); } } // call stack management. Represent data coming from the debug service. private onFocusStackFrame(): void { - Object.keys(this.modelData).forEach(modelUrlStr => { - const modelData = this.modelData[modelUrlStr]; - modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(modelUrlStr)); + this.modelDataMap.forEach((modelData, uri) => { + modelData.currentStackDecorations = modelData.model.deltaDecorations(modelData.currentStackDecorations, this.createCallStackDecorations(uri)); }); } - private createCallStackDecorations(modelUrlStr: string): IModelDeltaDecoration[] { + private createCallStackDecorations(modelUriStr: string): IModelDeltaDecoration[] { const result: IModelDeltaDecoration[] = []; const stackFrame = this.debugService.getViewModel().focusedStackFrame; - if (!stackFrame || stackFrame.source.uri.toString() !== modelUrlStr) { + if (!stackFrame || stackFrame.source.uri.toString() !== modelUriStr) { return result; } @@ -140,15 +139,16 @@ export class DebugEditorModelManager implements IWorkbenchContribution { range: wholeLineRange }); - if (this.modelData[modelUrlStr]) { - if (this.modelData[modelUrlStr].topStackFrameRange && this.modelData[modelUrlStr].topStackFrameRange.startLineNumber === wholeLineRange.startLineNumber && - this.modelData[modelUrlStr].topStackFrameRange.startColumn !== wholeLineRange.startColumn) { + if (this.modelDataMap.has(modelUriStr)) { + const modelData = this.modelDataMap.get(modelUriStr); + if (modelData.topStackFrameRange && modelData.topStackFrameRange.startLineNumber === wholeLineRange.startLineNumber && + modelData.topStackFrameRange.startColumn !== wholeLineRange.startColumn) { result.push({ options: DebugEditorModelManager.TOP_STACK_FRAME_COLUMN_DECORATION, range: wholeLineRange }); } - this.modelData[modelUrlStr].topStackFrameRange = wholeLineRange; + modelData.topStackFrameRange = wholeLineRange; } } } else { @@ -168,22 +168,21 @@ export class DebugEditorModelManager implements IWorkbenchContribution { // breakpoints management. Represent data coming from the debug service and also send data back. private onModelDecorationsChanged(modelUrlStr: string, e: IModelDecorationsChangedEvent): void { - const modelData = this.modelData[modelUrlStr]; - let myDecorationsCount = Object.keys(modelData.breakpointDecorationsAsMap).length; - if (myDecorationsCount === 0) { + const modelData = this.modelDataMap.get(modelUrlStr); + if (modelData.breakpointDecorationsAsMap.size === 0) { // I have no decorations return; } - if (!e.changedDecorations.some(decorationId => modelData.breakpointDecorationsAsMap[decorationId])) { + if (!e.changedDecorations.some(decorationId => modelData.breakpointDecorationsAsMap.has(decorationId))) { // nothing to do, my decorations did not change. return; } const data: IRawBreakpoint[] = []; - const lineToBreakpointDataMap: { [key: number]: IBreakpoint } = {}; + const lineToBreakpointDataMap = new Map(); this.debugService.getModel().getBreakpoints().filter(bp => bp.uri.toString() === modelUrlStr).forEach(bp => { - lineToBreakpointDataMap[bp.lineNumber] = bp; + lineToBreakpointDataMap.set(bp.lineNumber, bp); }); const modelUri = modelData.model.uri; @@ -192,13 +191,14 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const lineNumber = modelData.breakpointLines[i]; // check if the line got deleted. if (decorationRange.endColumn - decorationRange.startColumn > 0) { + const breakpoint = lineToBreakpointDataMap.get(lineNumber); // since we know it is collapsed, it cannot grow to multiple lines data.push({ lineNumber: decorationRange.startLineNumber, - enabled: lineToBreakpointDataMap[lineNumber].enabled, - condition: lineToBreakpointDataMap[lineNumber].condition, - hitCondition: lineToBreakpointDataMap[lineNumber].hitCondition, - column: lineToBreakpointDataMap[lineNumber].column + enabled: breakpoint.enabled, + condition: breakpoint.condition, + hitCondition: breakpoint.hitCondition, + column: breakpoint.column }); } } @@ -213,31 +213,32 @@ export class DebugEditorModelManager implements IWorkbenchContribution { } private onBreakpointsChange(): void { - const breakpointsMap: { [key: string]: IBreakpoint[] } = Object.create(null); + const breakpointsMap = new Map(); this.debugService.getModel().getBreakpoints().forEach(bp => { const uriStr = bp.uri.toString(); - if (breakpointsMap[uriStr]) { - breakpointsMap[uriStr].push(bp); + if (breakpointsMap.has(uriStr)) { + breakpointsMap.get(uriStr).push(bp); } else { - breakpointsMap[uriStr] = [bp]; + breakpointsMap.set(uriStr, [bp]); } }); - Object.keys(breakpointsMap).forEach(modelUriStr => { - if (this.modelData[modelUriStr]) { - this.updateBreakpoints(this.modelData[modelUriStr], breakpointsMap[modelUriStr]); + breakpointsMap.forEach((bps, uri) => { + if (this.modelDataMap.has(uri)) { + this.updateBreakpoints(this.modelDataMap.get(uri), breakpointsMap.get(uri)); } }); - Object.keys(this.modelData).forEach(modelUriStr => { - if (!breakpointsMap[modelUriStr]) { - this.updateBreakpoints(this.modelData[modelUriStr], []); + this.modelDataMap.forEach((modelData, uri) => { + if (!breakpointsMap.has(uri)) { + this.updateBreakpoints(modelData, []); } }); } private updateBreakpoints(modelData: IDebugEditorModelData, newBreakpoints: IBreakpoint[]): void { modelData.breakpointDecorationIds = modelData.model.deltaDecorations(modelData.breakpointDecorationIds, this.createBreakpointDecorations(newBreakpoints)); - modelData.breakpointDecorationsAsMap = objects.toObject(modelData.breakpointDecorationIds, key => key, (key) => true); + modelData.breakpointDecorationsAsMap.clear(); + modelData.breakpointDecorationIds.forEach(id => modelData.breakpointDecorationsAsMap.set(id, true)); modelData.breakpointLines = newBreakpoints.map(bp => bp.lineNumber); } @@ -254,7 +255,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const activated = this.debugService.getModel().areBreakpointsActivated(); const state = this.debugService.state; const debugActive = state === State.Running || state === State.Stopped || state === State.Initializing; - const modelData = this.modelData[breakpoint.uri.toString()]; + const modelData = this.modelDataMap.get(breakpoint.uri.toString()); let result = (!breakpoint.enabled || !activated) ? DebugEditorModelManager.BREAKPOINT_DISABLED_DECORATION : debugActive && modelData && modelData.dirty && !breakpoint.verified ? DebugEditorModelManager.BREAKPOINT_DIRTY_DECORATION : diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 86188d6eb8d..c665252b3e5 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -14,6 +14,7 @@ import { ISuggestion } from 'vs/editor/common/modes'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; import { Range } from 'vs/editor/common/core/range'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; export const VIEWLET_ID = 'workbench.view.debug'; export const REPL_ID = 'workbench.panel.repl'; @@ -170,6 +171,7 @@ export interface IStackFrame extends ITreeElement { getScopes(): TPromise; restart(): TPromise; toString(): string; + openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise; } export interface IEnablement extends ITreeElement { diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 0562753bed2..9a6b23de05b 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -19,6 +19,7 @@ import { ISuggestion } from 'vs/editor/common/modes'; import { Position } from 'vs/editor/common/core/position'; import * as debug from 'vs/workbench/parts/debug/common/debug'; import { Source } from 'vs/workbench/parts/debug/common/debugSource'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; const MAX_REPL_LENGTH = 10000; const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); @@ -90,7 +91,7 @@ export class OutputNameValueElement extends AbstractOutputElement implements deb export class ExpressionContainer implements debug.IExpressionContainer { - public static allValues: { [id: string]: string } = {}; + public static allValues: Map = new Map(); // Use chunks to support variable paging #9537 private static BASE_CHUNK_SIZE = 100; @@ -173,9 +174,9 @@ export class ExpressionContainer implements debug.IExpressionContainer { public set value(value: string) { this._value = value; - this.valueChanged = ExpressionContainer.allValues[this.getId()] && - ExpressionContainer.allValues[this.getId()] !== Expression.DEFAULT_VALUE && ExpressionContainer.allValues[this.getId()] !== value; - ExpressionContainer.allValues[this.getId()] = value; + this.valueChanged = ExpressionContainer.allValues.get(this.getId()) && + ExpressionContainer.allValues.get(this.getId()) !== Expression.DEFAULT_VALUE && ExpressionContainer.allValues.get(this.getId()) !== value; + ExpressionContainer.allValues.set(this.getId(), value); } } @@ -351,6 +352,19 @@ export class StackFrame implements debug.IStackFrame { public toString(): string { return `${this.name} (${this.source.inMemory ? this.source.name : this.source.uri.fsPath}:${this.lineNumber})`; } + + public openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise { + return editorService.openEditor({ + resource: this.source.uri, + description: this.source.origin, + options: { + preserveFocus, + selection: { startLineNumber: this.lineNumber, startColumn: 1 }, + revealIfVisible: true, + revealInCenterIfOutsideViewport: true + } + }, sideBySide); + } } export class Thread implements debug.IThread { @@ -463,10 +477,10 @@ export class Thread implements debug.IThread { export class Process implements debug.IProcess { - private threads: { [reference: number]: Thread; }; + private threads: Map; constructor(public name: string, private _session: debug.ISession & debug.ITreeElement) { - this.threads = {}; + this.threads = new Map(); } public get session(): debug.ISession { @@ -474,11 +488,13 @@ export class Process implements debug.IProcess { } public getThread(threadId: number): Thread { - return this.threads[threadId]; + return this.threads.get(threadId); } public getAllThreads(): debug.IThread[] { - return Object.keys(this.threads).map(key => this.threads[key]); + const result = []; + this.threads.forEach(t => result.push(t)); + return result; } public getId(): string { @@ -487,66 +503,66 @@ export class Process implements debug.IProcess { public rawUpdate(data: debug.IRawModelUpdate): void { - if (data.thread && !this.threads[data.threadId]) { + if (data.thread && !this.threads.has(data.threadId)) { // A new thread came in, initialize it. - this.threads[data.threadId] = new Thread(this, data.thread.name, data.thread.id); + this.threads.set(data.threadId, new Thread(this, data.thread.name, data.thread.id)); } if (data.stoppedDetails) { // Set the availability of the threads' callstacks depending on // whether the thread is stopped or not if (data.allThreadsStopped) { - Object.keys(this.threads).forEach(ref => { + this.threads.forEach(thread => { // Only update the details if all the threads are stopped // because we don't want to overwrite the details of other // threads that have stopped for a different reason - this.threads[ref].stoppedDetails = clone(data.stoppedDetails); - this.threads[ref].stopped = true; - this.threads[ref].clearCallStack(); + thread.stoppedDetails = clone(data.stoppedDetails); + thread.stopped = true; + thread.clearCallStack(); }); } else { // One thread is stopped, only update that thread. - this.threads[data.threadId].stoppedDetails = data.stoppedDetails; - this.threads[data.threadId].clearCallStack(); - this.threads[data.threadId].stopped = true; + const thread = this.threads.get(data.threadId); + thread.stoppedDetails = data.stoppedDetails; + thread.clearCallStack(); + thread.stopped = true; } } } public clearThreads(removeThreads: boolean, reference: number = undefined): void { if (reference) { - if (this.threads[reference]) { - this.threads[reference].clearCallStack(); - this.threads[reference].stoppedDetails = undefined; - this.threads[reference].stopped = false; + if (this.threads.has(reference)) { + const thread = this.threads.get(reference); + thread.clearCallStack(); + thread.stoppedDetails = undefined; + thread.stopped = false; if (removeThreads) { - delete this.threads[reference]; + this.threads.delete(reference); } } } else { - Object.keys(this.threads).forEach(ref => { - this.threads[ref].clearCallStack(); - this.threads[ref].stoppedDetails = undefined; - this.threads[ref].stopped = false; + this.threads.forEach(thread => { + thread.clearCallStack(); + thread.stoppedDetails = undefined; + thread.stopped = false; }); if (removeThreads) { - this.threads = {}; - ExpressionContainer.allValues = {}; + this.threads.clear(); + ExpressionContainer.allValues.clear(); } } } public sourceIsUnavailable(uri: uri): void { - Object.keys(this.threads).forEach(key => { - if (this.threads[key].getCachedCallStack()) { - this.threads[key].getCachedCallStack().forEach(stackFrame => { - if (stackFrame.source.uri.toString() === uri.toString()) { - stackFrame.source.available = false; - } - }); - } + this.threads.forEach(thread => { + thread.getCallStack().forEach(stackFrame => { + if (stackFrame.source.uri.toString() === uri.toString()) { + stackFrame.source.available = false; + } + }); }); } diff --git a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts index 790de1fcc91..21c69e61090 100644 --- a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts @@ -1042,11 +1042,11 @@ declare module DebugProtocol { /** A Source is a descriptor for source code. It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints. */ export interface Source { - /** The short name of the source. Every source returned from the debug adapter has a name. When specifying a source to the debug adapter this name is optional. */ + /** The short name of the source. Every source returned from the debug adapter has a name. When sending a source to the debug adapter this name is optional. */ name?: string; - /** The long (absolute) path of the source. It is not guaranteed that the source exists at this location. */ + /** The path of the source to be shown in the UI. It is only used to locate and load the content of the source if no sourceReference is specified (or its vaule is 0). */ path?: string; - /** If sourceReference > 0 the contents of the source can be retrieved through the SourceRequest. A sourceReference is only valid for a session, so it must not be used to persist a source. */ + /** If sourceReference > 0 the contents of the source must be retrieved through the SourceRequest (even if a path is specified). A sourceReference is only valid for a session, so it must not be used to persist a source. */ sourceReference?: number; /** The (optional) origin of this source: possible values 'internal module', 'inlined content from source map', etc. */ origin?: string; @@ -1218,7 +1218,7 @@ declare module DebugProtocol { } /** Some predefined types for the CompletionItem. Please note that not all clients have specific icons for all of them. */ - export type CompletionItemType = 'method' | 'function' | 'constructor' | 'field' | 'variable' | 'class' | 'interface' | 'module' | 'property' | 'unit' | 'value' | 'enum' | 'keyword' | 'snippet' | 'text' | 'color' | 'file' | 'reference' | 'customcolor' | 'folder'; + export type CompletionItemType = 'method' | 'function' | 'constructor' | 'field' | 'variable' | 'class' | 'interface' | 'module' | 'property' | 'unit' | 'value' | 'enum' | 'keyword' | 'snippet' | 'text' | 'color' | 'file' | 'reference' | 'customcolor'; /** Names of checksum algorithms that may be supported by a debug adapter. */ export type ChecksumAlgorithm = 'MD5' | 'SHA1' | 'SHA256' | 'SHA1Normalized' | 'SHA256Normalized' | 'timestamp'; diff --git a/src/vs/workbench/parts/debug/common/debugSource.ts b/src/vs/workbench/parts/debug/common/debugSource.ts index df728f73675..e51a24cfefb 100644 --- a/src/vs/workbench/parts/debug/common/debugSource.ts +++ b/src/vs/workbench/parts/debug/common/debugSource.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import uri from 'vs/base/common/uri'; -import * as paths from 'vs/base/common/paths'; import { DEBUG_SCHEME } from 'vs/workbench/parts/debug/common/debug'; export class Source { @@ -15,7 +14,8 @@ export class Source { private static INTERNAL_URI_PREFIX = `${DEBUG_SCHEME}://internal/`; constructor(public raw: DebugProtocol.Source, available = true) { - this.uri = raw.path ? uri.file(paths.normalize(raw.path)) : uri.parse(Source.INTERNAL_URI_PREFIX + raw.sourceReference + '/' + raw.name); + const path = raw.path || raw.name; + this.uri = raw.sourceReference > 0 ? uri.parse(Source.INTERNAL_URI_PREFIX + raw.sourceReference + '/' + path) : uri.file(path); this.available = available; } diff --git a/src/vs/workbench/parts/debug/common/replHistory.ts b/src/vs/workbench/parts/debug/common/replHistory.ts index 9ed159fe91b..92beb99600d 100644 --- a/src/vs/workbench/parts/debug/common/replHistory.ts +++ b/src/vs/workbench/parts/debug/common/replHistory.ts @@ -17,12 +17,12 @@ export class ReplHistory { private historyPointer: number; private currentExpressionStoredMarkers: boolean; - private historyOverwrites: { [position: string]: string; }; + private historyOverwrites: Map; constructor(private history: string[]) { this.historyPointer = this.history.length; this.currentExpressionStoredMarkers = false; - this.historyOverwrites = {}; + this.historyOverwrites = new Map(); } public next(): string { @@ -48,8 +48,8 @@ export class ReplHistory { this.historyPointer = newPointer; // check for overwrite - if (this.historyOverwrites && this.historyOverwrites[newPointer.toString()]) { - return this.historyOverwrites[newPointer.toString()]; + if (this.historyOverwrites.has(newPointer.toString())) { + return this.historyOverwrites.get(newPointer.toString()); } return this.history[newPointer]; @@ -78,11 +78,7 @@ export class ReplHistory { // keep edits that are made to history items up until the user actually evaluates a expression else { - if (!this.historyOverwrites) { - this.historyOverwrites = {}; - } - - this.historyOverwrites[previousPointer.toString()] = expression; + this.historyOverwrites.set(previousPointer.toString(), expression); } } @@ -104,7 +100,7 @@ export class ReplHistory { this.currentExpressionStoredMarkers = false; // reset overwrites - this.historyOverwrites = null; + this.historyOverwrites.clear(); } public save(): string[] { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index c165bb471e6..e58380990f8 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -193,7 +193,7 @@ jsonRegistry.registerSchema(schemaId, schema); export class ConfigurationManager implements debug.IConfigurationManager { private adapters: Adapter[]; - private allModeIdsForBreakpoints: { [key: string]: boolean }; + private breakpointModeIdsSet: Set; constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @@ -208,7 +208,7 @@ export class ConfigurationManager implements debug.IConfigurationManager { ) { this.adapters = []; this.registerListeners(); - this.allModeIdsForBreakpoints = {}; + this.breakpointModeIdsSet = new Set(); } private registerListeners(): void { @@ -220,7 +220,7 @@ export class ConfigurationManager implements debug.IConfigurationManager { } if (rawAdapter.enableBreakpointsFor) { rawAdapter.enableBreakpointsFor.languageIds.forEach(modeId => { - this.allModeIdsForBreakpoints[modeId] = true; + this.breakpointModeIdsSet.add(modeId); }); } @@ -250,7 +250,7 @@ export class ConfigurationManager implements debug.IConfigurationManager { breakpointsExtPoint.setHandler(extensions => { extensions.forEach(ext => { ext.value.forEach(breakpoints => { - this.allModeIdsForBreakpoints[breakpoints.language] = true; + this.breakpointModeIdsSet.add(breakpoints.language); }); }); }); @@ -385,6 +385,6 @@ export class ConfigurationManager implements debug.IConfigurationManager { const modeId = model ? model.getLanguageIdentifier().language : null; - return !!this.allModeIdsForBreakpoints[modeId]; + return this.breakpointModeIdsSet.has(modeId); } } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index ad7f1883698..75c04ff7cde 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -59,7 +59,7 @@ const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname'; export class DebugService implements debug.IDebugService { public _serviceBrand: any; - private sessionStates: { [id: string]: debug.State }; + private sessionStates: Map; private _onDidChangeState: Emitter; private model: Model; private viewModel: ViewModel; @@ -67,9 +67,9 @@ export class DebugService implements debug.IDebugService { private customTelemetryService: ITelemetryService; private lastTaskEvent: TaskEvent; private toDispose: lifecycle.IDisposable[]; - private toDisposeOnSessionEnd: { [id: string]: lifecycle.IDisposable[] }; + private toDisposeOnSessionEnd: Map; private inDebugMode: IContextKey; - private breakpointsToSendOnResourceSaved: { [uri: string]: boolean }; + private breakpointsToSendOnResourceSaved: Set; constructor( @IStorageService private storageService: IStorageService, @@ -93,10 +93,10 @@ export class DebugService implements debug.IDebugService { @IConfigurationService private configurationService: IConfigurationService ) { this.toDispose = []; - this.toDisposeOnSessionEnd = {}; - this.breakpointsToSendOnResourceSaved = {}; + this.toDisposeOnSessionEnd = new Map(); + this.breakpointsToSendOnResourceSaved = new Set(); this._onDidChangeState = new Emitter(); - this.sessionStates = {}; + this.sessionStates = new Map(); this.configurationManager = this.instantiationService.createInstance(ConfigurationManager); this.inDebugMode = debug.CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService); @@ -236,8 +236,8 @@ export class DebugService implements debug.IDebugService { } private registerSessionListeners(process: Process, session: RawDebugSession): void { - this.toDisposeOnSessionEnd[session.getId()].push(session); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidInitialize(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session); + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidInitialize(event => { aria.status(nls.localize('debuggingStarted', "Debugging started.")); const sendConfigurationDone = () => { if (session && session.configuration.capabilities.supportsConfigurationDoneRequest) { @@ -255,7 +255,7 @@ export class DebugService implements debug.IDebugService { .done(() => this.fetchThreads(session), errors.onUnexpectedError); })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidStop(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidStop(event => { this.setStateAndEmit(session.getId(), debug.State.Stopped); const threadId = event.body.threadId; @@ -283,21 +283,14 @@ export class DebugService implements debug.IDebugService { this.windowService.getWindow().focus(); aria.alert(nls.localize('debuggingPaused', "Debugging paused, reason {0}, {1} {2}", event.body.reason, stackFrameToFocus.source ? stackFrameToFocus.source.name : '', stackFrameToFocus.lineNumber)); - return this.editorService.openEditor({ - resource: stackFrameToFocus.source.uri, - options: { - selection: { startLineNumber: stackFrameToFocus.lineNumber, startColumn: 1 }, - revealIfVisible: true, - revealInCenterIfOutsideViewport: true - } - }); + return stackFrameToFocus.openInEditor(this.editorService); } }); } }, errors.onUnexpectedError); })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidThread(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidThread(event => { if (event.body.reason === 'started') { this.fetchThreads(session).done(undefined, errors.onUnexpectedError); } else if (event.body.reason === 'exited') { @@ -305,7 +298,7 @@ export class DebugService implements debug.IDebugService { } })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidTerminateDebugee(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidTerminateDebugee(event => { aria.status(nls.localize('debuggingStopped', "Debugging stopped.")); if (session && session.getId() === event.body.sessionId) { if (event.body && typeof event.body.restart === 'boolean' && event.body.restart) { @@ -316,7 +309,7 @@ export class DebugService implements debug.IDebugService { } })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidContinued(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidContinued(event => { const threadId = event.body.allThreadsContinued ? undefined : event.body.threadId; this.model.clearThreads(session.getId(), false, threadId); if (this.viewModel.focusedProcess.getId() === session.getId()) { @@ -325,7 +318,7 @@ export class DebugService implements debug.IDebugService { this.setStateAndEmit(session.getId(), session.requestType === debug.SessionRequestType.LAUNCH_NO_DEBUG ? debug.State.RunningNoDebug : debug.State.Running); })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidOutput(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidOutput(event => { if (!event.body) { return; } @@ -351,7 +344,7 @@ export class DebugService implements debug.IDebugService { } })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidBreakpoint(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidBreakpoint(event => { const id = event.body && event.body.breakpoint ? event.body.breakpoint.id : undefined; const breakpoint = this.model.getBreakpoints().filter(bp => bp.idFromAdapter === id).pop(); if (breakpoint) { @@ -364,9 +357,9 @@ export class DebugService implements debug.IDebugService { } })); - this.toDisposeOnSessionEnd[session.getId()].push(session.onDidExitAdapter(event => { + this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidExitAdapter(event => { // 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905 - if (session && session.configuration.type === 'extensionHost' && this.sessionStates[session.getId()] === debug.State.RunningNoDebug) { + if (session && session.configuration.type === 'extensionHost' && this.sessionStates.get(session.getId()) === debug.State.RunningNoDebug) { this.windowsService.closeExtensionHostWindow(this.contextService.getWorkspace().resource.fsPath); } if (session && session.getId() === event.body.sessionId) { @@ -439,11 +432,11 @@ export class DebugService implements debug.IDebugService { const focusedProcess = this.viewModel.focusedProcess; if (focusedProcess) { - return this.sessionStates[focusedProcess.getId()]; + return this.sessionStates.get(focusedProcess.getId()); } const processes = this.model.getProcesses(); if (processes.length > 0) { - return this.sessionStates[processes[0].getId()]; + return this.sessionStates.get(processes[0].getId()); } return debug.State.Inactive; @@ -454,7 +447,7 @@ export class DebugService implements debug.IDebugService { } private setStateAndEmit(sessionId: string, newState: debug.State): void { - this.sessionStates[sessionId] = newState; + this.sessionStates.set(sessionId, newState); this._onDidChangeState.fire(); } @@ -671,9 +664,9 @@ export class DebugService implements debug.IDebugService { if (!this.viewModel.focusedProcess) { this.focusStackFrameAndEvaluate(null, process); } - this.toDisposeOnSessionEnd[session.getId()] = []; + this.toDisposeOnSessionEnd.set(session.getId(), []); if (client) { - this.toDisposeOnSessionEnd[session.getId()].push(client); + this.toDisposeOnSessionEnd.get(session.getId()).push(client); } this.registerSessionListeners(process, session); @@ -846,7 +839,7 @@ export class DebugService implements debug.IDebugService { }); try { - this.toDisposeOnSessionEnd[session.getId()] = lifecycle.dispose(this.toDisposeOnSessionEnd[session.getId()]); + this.toDisposeOnSessionEnd.set(session.getId(), lifecycle.dispose(this.toDisposeOnSessionEnd.get(session.getId()))); } catch (e) { // an internal module might be open so the dispose can throw -> ignore and continue with stop session. } @@ -903,7 +896,7 @@ export class DebugService implements debug.IDebugService { } if (this.textFileService.isDirty(modelUri)) { // Only send breakpoints for a file once it is not dirty #8077 - this.breakpointsToSendOnResourceSaved[modelUri.toString()] = true; + this.breakpointsToSendOnResourceSaved.add(modelUri.toString()); return TPromise.as(null); } @@ -998,8 +991,8 @@ export class DebugService implements debug.IDebugService { fileChangesEvent.contains(bp.uri, FileChangeType.DELETED))); fileChangesEvent.getUpdated().forEach(event => { - if (this.breakpointsToSendOnResourceSaved[event.resource.toString()]) { - this.breakpointsToSendOnResourceSaved[event.resource.toString()] = false; + if (this.breakpointsToSendOnResourceSaved.has(event.resource.toString())) { + this.breakpointsToSendOnResourceSaved.delete(event.resource.toString()); this.sendBreakpoints(event.resource, true).done(null, errors.onUnexpectedError); } }); @@ -1015,7 +1008,7 @@ export class DebugService implements debug.IDebugService { } public dispose(): void { - Object.keys(this.toDisposeOnSessionEnd).forEach(key => lifecycle.dispose(this.toDisposeOnSessionEnd[key])); + this.toDisposeOnSessionEnd.forEach(toDispose => lifecycle.dispose(toDispose)); this.toDispose = lifecycle.dispose(this.toDispose); } } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index c8e9b640f37..d82164b1452 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -309,15 +309,7 @@ export class CallStackController extends BaseDebugController { private focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { this.debugService.focusStackFrameAndEvaluate(stackFrame).then(() => { const sideBySide = (event && (event.ctrlKey || event.metaKey)); - return this.editorService.openEditor({ - resource: stackFrame.source.uri, - options: { - preserveFocus, - selection: { startLineNumber: stackFrame.lineNumber, startColumn: 1 }, - revealIfVisible: true, - revealInCenterIfOutsideViewport: true - }, - }, sideBySide); + return stackFrame.openInEditor(this.editorService, preserveFocus, sideBySide); }, errors.onUnexpectedError); } } @@ -563,7 +555,7 @@ export class CallStackRenderer implements IRenderer { private renderStackFrame(stackFrame: debug.IStackFrame, data: IStackFrameTemplateData): void { stackFrame.source.available ? dom.removeClass(data.stackFrame, 'disabled') : dom.addClass(data.stackFrame, 'disabled'); - data.file.title = stackFrame.source.uri.fsPath; + data.file.title = stackFrame.source.raw.path || stackFrame.source.name; data.label.textContent = stackFrame.name; data.label.title = stackFrame.name; data.fileName.textContent = getSourceName(stackFrame.source, this.contextService); diff --git a/src/vs/workbench/parts/debug/node/v8Protocol.ts b/src/vs/workbench/parts/debug/node/v8Protocol.ts index 3dd75e0e8db..8c368528db6 100644 --- a/src/vs/workbench/parts/debug/node/v8Protocol.ts +++ b/src/vs/workbench/parts/debug/node/v8Protocol.ts @@ -13,14 +13,14 @@ export abstract class V8Protocol { private outputStream: stream.Writable; private sequence: number; - private pendingRequests: { [id: number]: (e: DebugProtocol.Response) => void; }; + private pendingRequests: Map void>; private rawData: Buffer; private contentLength: number; constructor(private id: string) { this.sequence = 1; this.contentLength = -1; - this.pendingRequests = {}; + this.pendingRequests = new Map void>(); this.rawData = new Buffer(0); } @@ -77,7 +77,7 @@ export abstract class V8Protocol { if (clb) { // store callback for this request - this.pendingRequests[request.seq] = clb; + this.pendingRequests.set(request.seq, clb); } } @@ -130,9 +130,9 @@ export abstract class V8Protocol { break; case 'response': const response = rawData; - const clb = this.pendingRequests[response.request_seq]; + const clb = this.pendingRequests.get(response.request_seq); if (clb) { - delete this.pendingRequests[response.request_seq]; + this.pendingRequests.delete(response.request_seq); clb(response); } break; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css index a0d329f9f8f..8acfffe0567 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -3,157 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.quick-open-widget .extension { - padding: 0 14px 0 0; - height: 48px; -} - -.quick-open-widget .extension.loading, -.extensions-viewlet > .extensions .extension.loading, -.extension-editor > .body > .content.loading { - background: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjU3NSIgaGVpZ2h0PSI2cHgiPg0KICA8c3R5bGU+DQogICAgY2lyY2xlIHsNCiAgICAgIGFuaW1hdGlvbjogYmFsbCAyLjVzIGN1YmljLWJlemllcigwLjAwMCwgMS4wMDAsIDEuMDAwLCAwLjAwMCkgaW5maW5pdGU7DQogICAgICBmaWxsOiAjYmJiOw0KICAgIH0NCg0KICAgICNiYWxscyB7DQogICAgICBhbmltYXRpb246IGJhbGxzIDIuNXMgbGluZWFyIGluZmluaXRlOw0KICAgIH0NCg0KICAgICNjaXJjbGUyIHsgYW5pbWF0aW9uLWRlbGF5OiAwLjFzOyB9DQogICAgI2NpcmNsZTMgeyBhbmltYXRpb24tZGVsYXk6IDAuMnM7IH0NCiAgICAjY2lyY2xlNCB7IGFuaW1hdGlvbi1kZWxheTogMC4zczsgfQ0KICAgICNjaXJjbGU1IHsgYW5pbWF0aW9uLWRlbGF5OiAwLjRzOyB9DQoNCiAgICBAa2V5ZnJhbWVzIGJhbGwgew0KICAgICAgZnJvbSB7IHRyYW5zZm9ybTogbm9uZTsgfQ0KICAgICAgMjAlIHsgdHJhbnNmb3JtOiBub25lOyB9DQogICAgICA4MCUgeyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoODY0cHgpOyB9DQogICAgICB0byB7IHRyYW5zZm9ybTogdHJhbnNsYXRlWCg4NjRweCk7IH0NCiAgICB9DQoNCiAgICBAa2V5ZnJhbWVzIGJhbGxzIHsNCiAgICAgIGZyb20geyB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTQwcHgpOyB9DQogICAgICB0byB7IHRyYW5zZm9ybTogdHJhbnNsYXRlWCgzMHB4KTsgfQ0KICAgIH0NCiAgPC9zdHlsZT4NCiAgPGcgaWQ9ImJhbGxzIj4NCiAgICA8Y2lyY2xlIGNsYXNzPSJjaXJjbGUiIGlkPSJjaXJjbGUxIiBjeD0iLTExNSIgY3k9IjMiIHI9IjMiLz4NCiAgICA8Y2lyY2xlIGNsYXNzPSJjaXJjbGUiIGlkPSJjaXJjbGUyIiBjeD0iLTEzMCIgY3k9IjMiIHI9IjMiIC8+DQogICAgPGNpcmNsZSBjbGFzcz0iY2lyY2xlIiBpZD0iY2lyY2xlMyIgY3g9Ii0xNDUiIGN5PSIzIiByPSIzIiAvPg0KICAgIDxjaXJjbGUgY2xhc3M9ImNpcmNsZSIgaWQ9ImNpcmNsZTQiIGN4PSItMTYwIiBjeT0iMyIgcj0iMyIgLz4NCiAgICA8Y2lyY2xlIGNsYXNzPSJjaXJjbGUiIGlkPSJjaXJjbGU1IiBjeD0iLTE3NSIgY3k9IjMiIHI9IjMiIC8+DQogIDwvZz4NCjwvc3ZnPg==') center center no-repeat; -} - -.quick-open-widget .extension.loading > * { - opacity: 0.4; -} - -.quick-open-widget .extension .row { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - height: 24px; -} - -.quick-open-widget .extension .row .actions { - float: right; -} - -.quick-open-widget .extension .description { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - opacity: 0.6; -} - -.quick-open-widget .extension .install { - margin-left: 6px; - padding: 1px 3px; - border-radius: 3px; - background-color: rgba(132, 132, 132, 0.3); - font-size: smaller; - opacity: 0.7; -} - -.quick-open-widget .extension .install > .octicon { - font-size: small; - margin-right: 3px; -} - -.quick-open-widget .extension .icon.octicon-x:before { - margin-right: 2px; - margin-top: 2px; - display: inline-block; -} - -.quick-open-widget .extension .published { - float: right; - opacity: 0.6; - font-size: smaller; -} - -.quick-open-widget .extension .published > .version { - opacity: 0.6; - margin-right: 0.5em; -} - -@keyframes move-background { - to { background-position: 8px 0; } -} - -.quick-open-widget .extension .actions .action-item:not(.disabled) { - display: none; -} - -.quick-open-widget .monaco-tree-row:hover .extension .actions .action-item, -.quick-open-widget .monaco-tree-row.focused .extension .actions .action-item { - display: inherit; -} - -.quick-open-widget .extension .actions .action-item:not(:first-child) { - margin-left: 2px; -} - -.quick-open-widget .extension .actions .action-item { - line-height: 12px; -} - -.quick-open-widget .extension .actions .action-label { - width: 12px; - height: 12px; - font-size: smaller; - border: 1px solid rgba(132, 132, 132, 0.5); - /*border-radius: 2px;*/ - padding: 1px; - vertical-align: text-bottom; - text-transform: uppercase; - color: rgb(0, 157, 255); - border-color: rgb(0, 157, 255); -} - -.quick-open-widget .monaco-tree.focused .monaco-tree-row.focused .extension .actions .action-label:focus { - outline: 1px solid #DF740C; - outline-offset: -1px; -} - -.quick-open-widget .monaco-tree.focused .monaco-tree-row.focused .extension .actions .action-label:active { - outline: none; -} - -.quick-open-widget .extension .actions .action-label:not(.icon) { - padding: 1px 3px; - display: inline-block; - width: auto; - font-size: x-small; -} - -.quick-open-widget .extension .actions .action-item.disabled .action-label { - animation: move-background 0.5s linear infinite; - background-color: rgba(132, 132, 132, 0.5); - background-size: 8px; - background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.5) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0.5) 75%, transparent 75%, transparent); - color: rgb(0, 0, 0); - border-color: rgb(0, 0, 0); -} - -.quick-open-widget .extension .actions .action-item .action-label:hover { - text-decoration: none; -} - -.quick-open-widget .extension .actions .action-item:not(.disabled) .action-label:hover { - color: inherit; - background: rgba(132, 132, 132, 0.2); - border-color: #CCC; -} - -.quick-open-widget .extension .actions .action-item:not(.disabled) .action-label:active { - background: rgba(132, 132, 132, 0.5); -} - -.quick-open-widget .extension .actions .action-item:active { - transform: none; -} - -.monaco-workbench > .activitybar .monaco-action-bar .action-label.extensions { - background: url('extensions-status.svg') center center no-repeat; -} - -/* Global action */ - -.monaco-workbench > .activitybar .monaco-action-bar .action-label.extensions { - background-size: 22px; - background-repeat: no-repeat; - background-position: 50% !important; +.monaco-workbench > .activitybar > .content .monaco-action-bar .action-label.extensions { + background: url('extensions-status.svg') center center/22px no-repeat; } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 8006157ba6c..623df36d1cb 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -44,8 +44,8 @@ import { IInstantiationService, IConstructorSignature2 } from 'vs/platform/insta import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { Keybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { Selection } from 'vs/editor/common/core/selection'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; +import { IEditorViewState } from 'vs/editor/common/editorCommon'; export interface IEditableData { action: IAction; @@ -1307,13 +1307,13 @@ export abstract class BaseSaveFileAction extends BaseActionWithErrorReporting { encodingOfSource = textModel && textModel.getEncoding(); // text model can be null e.g. if this is a binary file! } - let selectionOfSource: Selection; + let viewStateOfSource: IEditorViewState; const activeEditor = this.editorService.getActiveEditor(); const editor = getCodeEditor(activeEditor); if (editor) { const activeResource = toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }); if (activeResource && activeResource.toString() === source.toString()) { - selectionOfSource = editor.getSelection(); + viewStateOfSource = editor.saveViewState(); } } @@ -1344,13 +1344,13 @@ export abstract class BaseSaveFileAction extends BaseActionWithErrorReporting { encoding: encodingOfSource, options: { pinned: true, - selection: selectionOfSource + viewState: viewStateOfSource } }; return this.editorService.replaceEditors([{ toReplace: { resource: source }, - replaceWith: replaceWith + replaceWith }]).then(() => true); }); } diff --git a/src/vs/workbench/parts/markers/browser/media/markers.css b/src/vs/workbench/parts/markers/browser/media/markers.css index 491e4ac3590..2cdcded90d2 100644 --- a/src/vs/workbench/parts/markers/browser/media/markers.css +++ b/src/vs/workbench/parts/markers/browser/media/markers.css @@ -46,10 +46,6 @@ line-height: 22px; } -.markers-panel .markers-panel-container .tree-container .markers-panel-tree-entry > * { - display: inline-block; -} - .markers-panel .markers-panel-container .tree-container .markers-panel-tree-entry .marker-stats { display: inline-block; margin-left: 10px; diff --git a/src/vs/workbench/parts/markers/common/markersModel.ts b/src/vs/workbench/parts/markers/common/markersModel.ts index bd7e75d2a24..ce4524b4ded 100644 --- a/src/vs/workbench/parts/markers/common/markersModel.ts +++ b/src/vs/workbench/parts/markers/common/markersModel.ts @@ -26,8 +26,8 @@ export class Resource { private _path: string = null; constructor(public uri: URI, public markers: Marker[], - public statistics: MarkerStatistics, - public matches: IMatch[] = []) { + public statistics: MarkerStatistics, + public matches: IMatch[] = []) { } public get path(): string { @@ -47,8 +47,8 @@ export class Resource { export class Marker { constructor(public id: string, public marker: IMarker, - public labelMatches: IMatch[] = [], - public sourceMatches: IMatch[] = []) { } + public labelMatches: IMatch[] = [], + public sourceMatches: IMatch[] = []) { } public get resource(): URI { return this.marker.resource; diff --git a/src/vs/workbench/parts/preferences/browser/media/preferences.css b/src/vs/workbench/parts/preferences/browser/media/preferences.css index 892ba87928d..6c31b27d5e7 100644 --- a/src/vs/workbench/parts/preferences/browser/media/preferences.css +++ b/src/vs/workbench/parts/preferences/browser/media/preferences.css @@ -102,10 +102,6 @@ color: white; } -.monaco-editor .settings-group-title-widget .title-container > * { - vertical-align: middle; - display: inline-block; -} .monaco-editor.vs-dark .settings-group-title-widget .title-container.focused, .monaco-editor.vs .settings-group-title-widget .title-container.focused { @@ -133,6 +129,11 @@ height: 16px; } +.monaco-editor .settings-group-title-widget .title-container > div { + vertical-align: middle; + display: inline-block; +} + .monaco-editor.vs-dark .settings-group-title-widget .title-container .expand-collapse-icon, .monaco-editor.hc-black .settings-group-title-widget .title-container .expand-collapse-icon { background: url(expanded-dark.svg) 50% 50% no-repeat; diff --git a/src/vs/workbench/parts/search/browser/media/searchviewlet.css b/src/vs/workbench/parts/search/browser/media/searchviewlet.css index b4f7cb01317..11a0c709922 100644 --- a/src/vs/workbench/parts/search/browser/media/searchviewlet.css +++ b/src/vs/workbench/parts/search/browser/media/searchviewlet.css @@ -42,18 +42,15 @@ .search-viewlet .search-widget .replace-container { margin-top: 6px; position: relative; + display: inline-flex; + height: 25px; } .search-viewlet .search-widget .replace-container.disabled { display: none; } -.search-viewlet .search-widget .replace-container > * { - display: inline-block; -} - .search-viewlet .search-widget .replace-container .monaco-action-bar { - position: absolute; margin-left: 3px; } diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index 9847b83b1f0..e2ba6cde2ed 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as timer from 'vs/base/common/timer'; import paths = require('vs/base/common/paths'); import objects = require('vs/base/common/objects'); import strings = require('vs/base/common/strings'); @@ -544,14 +543,12 @@ export class SearchModel extends Disposable { this._searchResult.query = this._searchQuery.contentPattern; this._replacePattern = new ReplacePattern(this._replaceString, this._searchQuery.contentPattern); - const timerEvent = timer.start(timer.Topic.WORKBENCH, 'Search'); this.currentRequest = this.searchService.search(this._searchQuery); const onDone = fromPromise(this.currentRequest); const onDoneStopwatch = stopwatch(onDone); const start = Date.now(); - onDone(() => timerEvent.stop()); onDoneStopwatch(duration => this.telemetryService.publicLog('searchResultsFinished', { duration })); const progressEmitter = new Emitter(); diff --git a/src/vs/workbench/parts/search/test/common/searchModel.test.ts b/src/vs/workbench/parts/search/test/common/searchModel.test.ts index 3a5417c1ff8..ca52028f261 100644 --- a/src/vs/workbench/parts/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/parts/search/test/common/searchModel.test.ts @@ -9,7 +9,6 @@ import * as sinon from 'sinon'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { DeferredPPromise } from 'vs/base/test/common/utils'; import { PPromise } from 'vs/base/common/winjs.base'; -import { nullEvent } from 'vs/base/common/timer'; import { SearchModel } from 'vs/workbench/parts/search/common/searchModel'; import URI from 'vs/base/common/uri'; import { IFileMatch, ILineMatch, ISearchService, ISearchComplete, ISearchProgressItem, IUncachedSearchStats } from 'vs/platform/search/common/search'; @@ -20,6 +19,27 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +const nullEvent = new class { + + public id: number; + public topic: string; + public name: string; + public description: string; + public data: any; + + public startTime: Date; + public stopTime: Date; + + public stop(): void { + return; + } + + public timeTaken(): number { + return -1; + } +}; + + suite('SearchModel', () => { let instantiationService: TestInstantiationService; @@ -292,4 +312,4 @@ suite('SearchModel', () => { return instantiationService.createInstance(ModelServiceImpl); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index f27caed5b94..f6c97a0c0b4 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -181,17 +181,17 @@ /* Base selection colors */ -.monaco-workbench .panel.integrated-terminal .xterm *::selection { +.monaco-workbench .panel.integrated-terminal .xterm ::selection { color: #FFF; background-color: rgba(51, 51, 51, 0.996); } -.vs-dark .monaco-workbench .panel.integrated-terminal .xterm *::selection { +.vs-dark .monaco-workbench .panel.integrated-terminal .xterm ::selection { color: #1e1e1e; background-color: rgba(204, 204, 204, 0.996); } -.hc-black .monaco-workbench .panel.integrated-terminal .xterm *::selection { +.hc-black .monaco-workbench .panel.integrated-terminal .xterm ::selection { color: #000; background-color: rgba(255, 255, 255, 0.996); } diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index c0949423672..4aa82872e94 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -227,7 +227,7 @@ export class SwitchTerminalInstanceAction extends Action { } public run(item?: string): TPromise { - if (!item) { + if (!item || !item.split) { return TPromise.as(null); } const selectedTerminalIndex = parseInt(item.split(':')[0], 10) - 1; diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 9da33446228..d622ec34313 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -562,7 +562,7 @@ export abstract class TextFileService implements ITextFileService { private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { // create the target file empty if it does not exist already - return this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.createFile(target)).then(stat => { + return this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.updateContent(target, '')).then(stat => { // resolve a model for the file (which can be binary if the file is not a text file) return this.models.loadOrCreate(target).then((targetModel: ITextFileEditorModel) => { diff --git a/src/vs/workbench/services/timer/common/timerService.ts b/src/vs/workbench/services/timer/common/timerService.ts index 8366aa6fe64..19d7c77d7ba 100644 --- a/src/vs/workbench/services/timer/common/timerService.ts +++ b/src/vs/workbench/services/timer/common/timerService.ts @@ -19,6 +19,7 @@ export interface IStartupMetrics { version: number; ellapsed: number; timers: { + ellapsedAppReady?: number; ellapsedWindowLoad?: number; ellapsedWindowLoadToRequire: number; ellapsedExtensions: number; @@ -44,6 +45,8 @@ export interface IStartupMetrics { export interface IInitData { start: Date; + appReady: Date; + windowLoad: Date; beforeLoadWorkbenchMain: Date; @@ -69,4 +72,4 @@ export interface ITimerService extends IInitData { restoreEditorsDuration: number; readonly startupMetrics: IStartupMetrics; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/timer/node/timerService.ts b/src/vs/workbench/services/timer/node/timerService.ts index a0eb9caa6f1..ffec104d14e 100644 --- a/src/vs/workbench/services/timer/node/timerService.ts +++ b/src/vs/workbench/services/timer/node/timerService.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as timer from 'vs/base/common/timer'; import { ITimerService, IStartupMetrics, IInitData, IMemoryInfo } from 'vs/workbench/services/timer/common/timerService'; import * as os from 'os'; @@ -13,21 +12,15 @@ export class TimerService implements ITimerService { public _serviceBrand: any; - public get start(): Date { return this._start; } - private _start: Date; + public readonly start: Date; + public readonly appReady: Date; + public readonly windowLoad: Date; - public get windowLoad(): Date { return this._windowLoad; }; - private _windowLoad: Date; + public readonly beforeLoadWorkbenchMain: Date; + public readonly afterLoadWorkbenchMain: Date; - public get beforeLoadWorkbenchMain(): Date { return this._beforeLoadWorkbenchMain; }; - private _beforeLoadWorkbenchMain: Date; - public get afterLoadWorkbenchMain(): Date { return this._afterLoadWorkbenchMain; }; - private _afterLoadWorkbenchMain: Date; - - public get isInitialStartup(): boolean { return this._isInitialStartup; }; - private _isInitialStartup: boolean; - public get hasAccessibilitySupport(): boolean { return this._hasAccessibilitySupport; }; - private _hasAccessibilitySupport: boolean; + public readonly isInitialStartup: boolean; + public readonly hasAccessibilitySupport: boolean; public beforeDOMContentLoaded: Date; public afterDOMContentLoaded: Date; @@ -51,18 +44,15 @@ export class TimerService implements ITimerService { private _startupMetrics: IStartupMetrics; constructor(initData: IInitData, private isEmptyWorkbench: boolean) { - this._start = initData.start; + this.start = initData.start; + this.appReady = initData.appReady; + this.windowLoad = initData.windowLoad; - this._windowLoad = initData.windowLoad; + this.beforeLoadWorkbenchMain = initData.beforeLoadWorkbenchMain; + this.afterLoadWorkbenchMain = initData.afterLoadWorkbenchMain; - this._beforeLoadWorkbenchMain = initData.beforeLoadWorkbenchMain; - this._afterLoadWorkbenchMain = initData.afterLoadWorkbenchMain; - - this._isInitialStartup = initData.isInitialStartup; - this._hasAccessibilitySupport = initData.hasAccessibilitySupport; - - // forward start time to time keeper - timer.TimeKeeper.PARSE_TIME = initData.isInitialStartup ? initData.start : initData.windowLoad; + this.isInitialStartup = initData.isInitialStartup; + this.hasAccessibilitySupport = initData.hasAccessibilitySupport; } public computeStartupMetrics(): void { @@ -120,7 +110,8 @@ export class TimerService implements ITimerService { }; if (initialStartup) { - this._startupMetrics.timers.ellapsedWindowLoad = Math.round(this.windowLoad.getTime() - this.start.getTime()); + this._startupMetrics.timers.ellapsedAppReady = Math.round(this.appReady.getTime() - this.start.getTime()); + this._startupMetrics.timers.ellapsedWindowLoad = Math.round(this.windowLoad.getTime() - this.appReady.getTime()); } } -} \ No newline at end of file +} diff --git a/src/vs/workbench/test/electron-browser/quickopen.perf.test.ts b/src/vs/workbench/test/electron-browser/quickopen.perf.test.ts index 52845c580bb..1d325306e0a 100644 --- a/src/vs/workbench/test/electron-browser/quickopen.perf.test.ts +++ b/src/vs/workbench/test/electron-browser/quickopen.perf.test.ts @@ -22,7 +22,6 @@ import { SearchService } from 'vs/workbench/services/search/node/searchService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { TestEnvironmentService, TestEditorService, TestEditorGroupService } from 'vs/workbench/test/workbenchTestServices'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import * as Timer from 'vs/base/common/timer'; import { TPromise } from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; @@ -31,6 +30,23 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; + +namespace Timer { + export interface ITimerEvent { + id: number; + topic: string; + name: string; + description: string; + data: any; + + startTime: Date; + stopTime: Date; + + stop(stopTime?: Date): void; + timeTaken(): number; + } +} + declare var __dirname: string; // Checkout sources to run against: