diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 94f73f29b9d..908405e3b3e 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.8.5' }, + { name: 'ms-vscode.node-debug', version: '1.8.7' }, { name: 'ms-vscode.node-debug2', version: '1.8.2' } ]; diff --git a/extensions/html/client/src/htmlMain.ts b/extensions/html/client/src/htmlMain.ts index 79de03d9f87..85fefd16523 100644 --- a/extensions/html/client/src/htmlMain.ts +++ b/extensions/html/client/src/htmlMain.ts @@ -50,17 +50,14 @@ export function activate(context: ExtensionContext) { // Create the language client and start the client. let client = new LanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), serverOptions, clientOptions, true); let disposable = client.start(); - - // Push the disposable to the context's subscriptions so that the - // client can be deactivated on extension deactivation context.subscriptions.push(disposable); - - let colorRequestor = (uri: string) => { - return client.sendRequest(ColorSymbolRequest.type, uri).then(ranges => ranges.map(client.protocol2CodeConverter.asRange)); - }; - disposable = activateColorDecorations(colorRequestor, { html: true, handlebars: true, razor: true }); - context.subscriptions.push(disposable); - + client.onReady().then(() => { + let colorRequestor = (uri: string) => { + return client.sendRequest(ColorSymbolRequest.type, uri).then(ranges => ranges.map(client.protocol2CodeConverter.asRange)); + }; + let disposable = activateColorDecorations(colorRequestor, { html: true, handlebars: true, razor: true }); + context.subscriptions.push(disposable); + }); languages.setLanguageConfiguration('html', { wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, diff --git a/extensions/json/client/src/jsonMain.ts b/extensions/json/client/src/jsonMain.ts index 7dc61a32e1c..a00cc5ca01f 100644 --- a/extensions/json/client/src/jsonMain.ts +++ b/extensions/json/client/src/jsonMain.ts @@ -68,25 +68,26 @@ export function activate(context: ExtensionContext) { // Create the language client and start the client. let client = new LanguageClient('json', localize('jsonserver.name', 'JSON Language Server'), serverOptions, clientOptions); - client.onTelemetry(e => { - if (telemetryReporter) { - telemetryReporter.sendTelemetryEvent(e.key, e.data); - } - }); - - // handle content request - client.onRequest(VSCodeContentRequest.type, (uriPath: string) => { - let uri = Uri.parse(uriPath); - return workspace.openTextDocument(uri).then(doc => { - return doc.getText(); - }, error => { - return Promise.reject(error); - }); - }); - let disposable = client.start(); + client.onReady().then(() => { + client.onTelemetry(e => { + if (telemetryReporter) { + telemetryReporter.sendTelemetryEvent(e.key, e.data); + } + }); - client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); + // handle content request + client.onRequest(VSCodeContentRequest.type, (uriPath: string) => { + let uri = Uri.parse(uriPath); + return workspace.openTextDocument(uri).then(doc => { + return doc.getText(); + }, error => { + return Promise.reject(error); + }); + }); + + client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context)); + }); // Push the disposable to the context's subscriptions so that the // client can be deactivated on extension deactivation diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 0bbc1b7aa35..60b34043b6d 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -45,7 +45,7 @@ { "command": "markdown.showPreview", "title": "%markdown.preview.title%", - "category": "%markdown.category%", + "category": "Markdown", "icon": { "light": "./media/Preview.svg", "dark": "./media/Preview_inverse.svg" @@ -54,7 +54,7 @@ { "command": "markdown.showPreviewToSide", "title": "%markdown.previewSide.title%", - "category": "%markdown.category%", + "category": "Markdown", "icon": { "light": "./media/PreviewOnRightPane_16x.svg", "dark": "./media/PreviewOnRightPane_16x_dark.svg" @@ -63,7 +63,7 @@ { "command": "markdown.showSource", "title": "%markdown.showSource.title%", - "category": "%markdown.category%", + "category": "Markdown", "icon": { "light": "./media/ViewSource.svg", "dark": "./media/ViewSource_inverse.svg" @@ -120,12 +120,12 @@ "markdown.styles": { "type": ["array"], "default": [], - "description": "A list of URLs or local paths to CSS style sheets to use from the markdown preview. Relative paths are interpreted relative to the folder open in the explorer. If there is no open folder, they are interpreted relative to the location of the markdown file. All '\\' need to be written as '\\\\'." + "description": "%markdown.styles.dec%" }, "markdown.previewFrontMatter": { "type": ["string"], "default": "hide", - "description": "Sets how YAML front matter should be rendered in the markdown preview. 'hide' removes the front matter. Otherwise, the front matter is treated as markdown content" + "description": "%markdown.previewFrontMatter.dec%" } } } diff --git a/extensions/markdown/package.nls.json b/extensions/markdown/package.nls.json index dbf773dc25c..dbdafe5963f 100644 --- a/extensions/markdown/package.nls.json +++ b/extensions/markdown/package.nls.json @@ -1,6 +1,7 @@ { - "markdown.category" : "Markdown", "markdown.preview.title" : "Open Preview", "markdown.previewSide.title" : "Open Preview to the Side", - "markdown.showSource.title" : "Show Source" + "markdown.showSource.title" : "Show Source", + "markdown.styles.dec": "A list of URLs or local paths to CSS style sheets to use from the markdown preview. Relative paths are interpreted relative to the folder open in the explorer. If there is no open folder, they are interpreted relative to the location of the markdown file. All '\\' need to be written as '\\\\'.", + "markdown.previewFrontMatter.dec": "Sets how YAML front matter should be rendered in the markdown preview. 'hide' removes the front matter. Otherwise, the front matter is treated as markdown content" } \ No newline at end of file diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 160d9714293..8f6db221502 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -464,6 +464,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient allowSyntheticDefaultImports: true, allowNonTsExtensions: true, allowJs: true, + jsx: 'Preserve' }; let args: Proto.SetCompilerOptionsForInferredProjectsArgs = { options: compilerOptions diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 055e6678dfb..dca066d222e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -431,8 +431,8 @@ }, "xterm": { "version": "2.1.0", - "from": "xterm@2.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-2.1.0.tgz" + "from": "git+https://github.com/Tyriar/xterm.js.git#vscode-release/1.8", + "resolved": "git+https://github.com/Tyriar/xterm.js.git#81f0516e1098439116ac1344ae3074f51c5bcf52" }, "yauzl": { "version": "2.3.1", diff --git a/package.json b/package.json index bade2e77829..88c219a940a 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "vscode-debugprotocol": "1.14.0", "vscode-textmate": "2.3.1", "winreg": "1.2.0", - "xterm": "2.1.0", + "xterm": "git+https://github.com/Tyriar/xterm.js.git#vscode-release/1.8", "yauzl": "2.3.1" }, "devDependencies": { diff --git a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts index 45779c0ad24..a356d54f71d 100644 --- a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts @@ -127,7 +127,7 @@ export class ContextMenuController implements IEditorContribution { const result: IAction[] = []; let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); - const groups = contextMenu.getActions(); + const groups = contextMenu.getActions(this._editor.getModel().uri); contextMenu.dispose(); for (let group of groups) { diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 53c4988b6a5..47aaf34843e 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -183,7 +183,7 @@ export class FoldingController implements IFoldingController { this.decorations = newDecorations; }); if (updateHiddenRegions) { - this.updateHiddenAreas(void 0); + this.updateHiddenAreas(); } } @@ -327,7 +327,7 @@ export class FoldingController implements IFoldingController { }); } - private updateHiddenAreas(focusLine: number): void { + private updateHiddenAreas(focusLine?: number): void { let model = this.editor.getModel(); var selections: Selection[] = this.editor.getSelections(); var updateSelections = false; @@ -354,17 +354,13 @@ export class FoldingController implements IFoldingController { } }); }); - let revealPosition; - if (focusLine) { - revealPosition = { lineNumber: focusLine, column: 1 }; - } else { - revealPosition = selections[0].getStartPosition(); - } if (updateSelections) { this.editor.setSelections(selections); } this.editor.setHiddenAreas(hiddenAreas); - this.editor.revealPositionInCenterIfOutsideViewport(revealPosition); + if (focusLine) { + this.editor.revealPositionInCenterIfOutsideViewport({ lineNumber: focusLine, column: 1 }); + } } public unfold(levels: number): void { @@ -469,7 +465,7 @@ export class FoldingController implements IFoldingController { }); }); if (hasChanges) { - this.updateHiddenAreas(void 0); + this.updateHiddenAreas(this.editor.getPosition().lineNumber); } } } diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 06064172c72..a4e84f4aff9 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -123,6 +123,7 @@ export class SuggestController implements IEditorContribution { cancelSuggestWidget(): void { if (this.widget) { + this.model.cancel(); this.widget.hideDetailsOrHideWidget(); } } diff --git a/src/vs/platform/actions/browser/menuItemActionItem.ts b/src/vs/platform/actions/browser/menuItemActionItem.ts index b3222b7822e..64152cc193b 100644 --- a/src/vs/platform/actions/browser/menuItemActionItem.ts +++ b/src/vs/platform/actions/browser/menuItemActionItem.ts @@ -17,8 +17,8 @@ import { domEvent } from 'vs/base/browser/event'; import { Emitter } from 'vs/base/common/event'; -export function fillInActions(menu: IMenu, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }): void { - const groups = menu.getActions(); +export function fillInActions(menu: IMenu, context: any, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }): void { + const groups = menu.getActions(context); if (groups.length === 0) { return; } @@ -98,21 +98,18 @@ class MenuItemActionItem extends ActionItem { @IKeybindingService private _keybindingService: IKeybindingService, @IMessageService private _messageService: IMessageService ) { - super(undefined, action, { icon: !!action.command.iconClass, label: !action.command.iconClass }); + super(undefined, action, { icon: !!action.class, label: !action.class }); } private get _command() { - const {command, altCommand} = this._action; - return this._wantsAltCommand && altCommand || command; + return this._wantsAltCommand && (this._action).alt || this._action; } onClick(event: MouseEvent): void { event.preventDefault(); event.stopPropagation(); - (this._action).run(this._wantsAltCommand).done(undefined, err => { - this._messageService.show(Severity.Error, err); - }); + this._command.run().done(undefined, err => this._messageService.show(Severity.Error, err)); } render(container: HTMLElement): void { @@ -149,7 +146,7 @@ class MenuItemActionItem extends ActionItem { _updateLabel(): void { if (this.options.label) { - this.$e.text(this._command.title); + this.$e.text(this._command.label); } } @@ -159,20 +156,19 @@ class MenuItemActionItem extends ActionItem { const keybindingLabel = keybinding && this._keybindingService.getLabelFor(keybinding); element.title = keybindingLabel - ? localize('titleAndKb', "{0} ({1})", this._command.title, keybindingLabel) - : this._command.title; + ? localize('titleAndKb', "{0} ({1})", this._command.label, keybindingLabel) + : this._command.label; } _updateClass(): void { if (this.options.icon) { const element = this.$e.getHTMLElement(); - const {command, altCommand} = (this._action); - if (this._command !== command) { - element.classList.remove(command.iconClass); - } else if (altCommand) { - element.classList.remove(altCommand.iconClass); + if (this._command !== this._action) { + element.classList.remove(this._action.class); + } else if ((this._action).alt) { + element.classList.remove((this._action).alt.class); } - element.classList.add('icon', this._command.iconClass); + element.classList.add('icon', this._command.class); } } } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 6f601cfbe3e..c1a0eadd6e0 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import URI from 'vs/base/common/uri'; import { IAction, Action } from 'vs/base/common/actions'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; import { SyncDescriptor0, createSyncDescriptor, AsyncDescriptor0 } from 'vs/platform/instantiation/common/descriptors'; @@ -24,7 +23,7 @@ export interface ICommandAction { export interface IMenu extends IDisposable { onDidChange: Event; - getActions(): [string, IAction[]][]; + getActions(arg?: any): [string, MenuItemAction[]][]; } export interface IMenuItem { @@ -111,47 +110,6 @@ export const MenuRegistry: IMenuRegistry = new class { } }; - -export class MenuItemAction extends Action { - - private static _getMenuItemId(item: IMenuItem): string { - let result = item.command.id; - if (item.alt) { - result += `||${item.alt.id}`; - } - return result; - } - - constructor( - private _item: IMenuItem, - @ICommandService private _commandService: ICommandService, - @IContextKeyService private _contextKeyService: IContextKeyService - ) { - super(MenuItemAction._getMenuItemId(_item), _item.command.title); - - this.order = this._item.order; //TODO@Ben order is menu item property, not an action property - } - - get item(): IMenuItem { - return this._item; - } - - get command() { - return this._item.command; - } - - get altCommand() { - return this._item.alt; - } - - run(alt: boolean) { - const {id} = alt === true && this._item.alt || this._item.command; - const resource = this._contextKeyService.getContextKeyValue('resource'); - return this._commandService.executeCommand(id, resource); - } -} - - export class ExecuteCommandAction extends Action { constructor( @@ -167,6 +125,33 @@ export class ExecuteCommandAction extends Action { } } +export class MenuItemAction extends ExecuteCommandAction { + + private _arg: any; + + readonly item: ICommandAction; + readonly alt: MenuItemAction; + + constructor( + item: ICommandAction, + alt: ICommandAction, + arg: any, + @ICommandService commandService: ICommandService + ) { + super(item.id, item.title, commandService); + this._cssClass = item.iconClass; + this._enabled = true; + this._arg = arg; + + this.item = item; + this.alt = alt ? new MenuItemAction(alt, undefined, arg, commandService) : undefined; + } + + run(): TPromise { + return super.run(this._arg); + } +} + export class SyncActionDescriptor { private _descriptor: SyncDescriptor0; diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index 74d096dc3aa..575df57988c 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -7,7 +7,6 @@ import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IAction } from 'vs/base/common/actions'; import { values } from 'vs/base/common/collections'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry, ICommandAction, MenuItemAction, IMenu, IMenuItem, IMenuService } from 'vs/platform/actions/common/actions'; @@ -34,7 +33,7 @@ export class MenuService implements IMenuService { } } -type MenuItemGroup = [string, MenuItemAction[]]; +type MenuItemGroup = [string, IMenuItem[]]; class Menu implements IMenu { @@ -63,7 +62,7 @@ class Menu implements IMenu { group = [groupName, []]; this._menuGroups.push(group); } - group[1].push(new MenuItemAction(item, this._commandService, this._contextKeyService)); + group[1].push(item); // keep keys for eventing Menu._fillInKbExprKeys(item.when, keysFilter); @@ -92,13 +91,15 @@ class Menu implements IMenu { return this._onDidChange.event; } - getActions(): [string, IAction[]][] { - const result: MenuItemGroup[] = []; + getActions(arg?: any): [string, MenuItemAction[]][] { + const result: [string, MenuItemAction[]][] = []; for (let group of this._menuGroups) { - const [id, actions] = group; + const [id, items] = group; const activeActions: MenuItemAction[] = []; - for (let action of actions) { - if (this._contextKeyService.contextMatchesRules(action.item.when)) { + for (const item of items) { + if (this._contextKeyService.contextMatchesRules(item.when)) { + const action = new MenuItemAction(item.command, item.alt, arg, this._commandService); + action.order = item.order; //TODO@Ben order is menu item property, not an action property activeActions.push(action); } } diff --git a/src/vs/platform/actions/test/common/menuService.test.ts b/src/vs/platform/actions/test/common/menuService.test.ts index e35df331861..4cc8cc02d73 100644 --- a/src/vs/platform/actions/test/common/menuService.test.ts +++ b/src/vs/platform/actions/test/common/menuService.test.ts @@ -186,4 +186,4 @@ suite('MenuService', function () { assert.equal(two.id, 'b'); assert.equal(three.id, 'a'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/platform/telemetry/common/telemetry.ts b/src/vs/platform/telemetry/common/telemetry.ts index a9941458660..b766acbfd55 100644 --- a/src/vs/platform/telemetry/common/telemetry.ts +++ b/src/vs/platform/telemetry/common/telemetry.ts @@ -12,6 +12,7 @@ import URI from 'vs/base/common/uri'; import { ConfigurationSource, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const ITelemetryService = createDecorator('telemetryService'); @@ -22,8 +23,7 @@ export interface ITelemetryInfo { } export interface ITelemetryExperiments { - showDefaultViewlet: boolean; - showFirstSessionWatermark: boolean; + showNewUserWatermark: boolean; openUntitledFile: boolean; } @@ -45,8 +45,7 @@ export interface ITelemetryService { } export const defaultExperiments: ITelemetryExperiments = { - showDefaultViewlet: false, - showFirstSessionWatermark: false, + showNewUserWatermark: false, openUntitledFile: true }; @@ -69,7 +68,7 @@ export const NullTelemetryService = { } }; -export function loadExperiments(storageService: IStorageService, configurationService: IConfigurationService): ITelemetryExperiments { +export function loadExperiments(contextService: IWorkspaceContextService, storageService: IStorageService, configurationService: IConfigurationService): ITelemetryExperiments { const key = 'experiments.randomness'; let valueString = storageService.get(key); @@ -78,23 +77,20 @@ export function loadExperiments(storageService: IStorageService, configurationSe storageService.store(key, valueString); } - const random0 = parseFloat(valueString); - let [random1, showDefaultViewlet] = splitRandom(random0); - let [random2, showFirstSessionWatermark] = splitRandom(random1); + const random1 = parseFloat(valueString); + let [random2, showNewUserWatermark] = splitRandom(random1); let [, openUntitledFile] = splitRandom(random2); - // is the user a first time user? - let isNewSession = storageService.get('telemetry.lastSessionDate') ? false : true; - if (!isNewSession) { - // for returning users we fall back to the default configuration for the sidebar and the initially opened, empty editor - showDefaultViewlet = defaultExperiments.showDefaultViewlet; - showFirstSessionWatermark = defaultExperiments.showFirstSessionWatermark; + const newUserDuration = 24 * 60 * 60 * 1000; + const firstSessionDate = storageService.get('telemetry.firstSessionDate'); + const isNewUser = !firstSessionDate || Date.now() - Date.parse(firstSessionDate) < newUserDuration; + if (!isNewUser || !!contextService.getWorkspace()) { + showNewUserWatermark = defaultExperiments.showNewUserWatermark; openUntitledFile = defaultExperiments.openUntitledFile; } return applyOverrides(configurationService, { - showDefaultViewlet, - showFirstSessionWatermark, + showNewUserWatermark, openUntitledFile }); } diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index ad138c4fb5a..398941992ac 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { EmitterEvent } from 'vs/base/common/eventEmitter'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -13,6 +12,7 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import URI from 'vs/base/common/uri'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IEventService } from 'vs/platform/event/common/event'; +import { getResource } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -21,12 +21,14 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { ExtHostContext, MainThreadDocumentsShape, ExtHostDocumentsShape } from './extHost.protocol'; import { ITextModelResolverService } from 'vs/editor/common/services/resolverService'; +import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; export class MainThreadDocuments extends MainThreadDocumentsShape { private _modelService: IModelService; private _modeService: IModeService; private _textModelResolverService: ITextModelResolverService; private _textFileService: ITextFileService; + private _codeEditorService: ICodeEditorService; private _editorService: IWorkbenchEditorService; private _fileService: IFileService; private _untitledEditorService: IUntitledEditorService; @@ -43,6 +45,7 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { @IModeService modeService: IModeService, @IEventService eventService: IEventService, @ITextFileService textFileService: ITextFileService, + @ICodeEditorService codeEditorService: ICodeEditorService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @ITextModelResolverService textModelResolverService: ITextModelResolverService, @@ -53,6 +56,7 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { this._modeService = modeService; this._textModelResolverService = textModelResolverService; this._textFileService = textFileService; + this._codeEditorService = codeEditorService; this._editorService = editorService; this._fileService = fileService; this._untitledEditorService = untitledEditorService; @@ -254,22 +258,32 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { const toBeDisposed: URI[] = []; - TPromise.join(Object.keys(this._virtualDocumentSet).map(key => { - let resource = URI.parse(key); - return this._editorService.createInput({ resource }).then(input => { - if (!this._editorService.isVisible(input, true)) { - toBeDisposed.push(resource); - } - - if (input) { - input.dispose(); - } - }); - })).then(() => { - for (let resource of toBeDisposed) { - this._modelService.destroyModel(resource); - delete this._virtualDocumentSet[resource.toString()]; + // list of uris used in editors + const activeResources: { [uri: string]: boolean } = Object.create(null); + for (const editor of this._codeEditorService.listCodeEditors()) { + if (editor.getModel()) { + activeResources[editor.getModel().uri.toString()] = true; } - }, onUnexpectedError); + } + + for (const workbenchEditor of this._editorService.getVisibleEditors()) { + const uri = getResource(workbenchEditor.input); + if (uri) { + activeResources[uri.toString()] = true; + } + } + + // intersect with virtual documents + for (let uri in this._virtualDocumentSet) { + if (!activeResources[uri]) { + toBeDisposed.push(URI.parse(uri)); + } + } + + // dispose unused virtual documents + for (let resource of toBeDisposed) { + this._modelService.destroyModel(resource); + delete this._virtualDocumentSet[resource.toString()]; + } } } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 3e6817ec209..26b01ca287f 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -332,7 +332,7 @@ export abstract class TitleControl implements ITitleAreaControl { const titleBarMenu = this.menuService.createMenu(MenuId.EditorTitle, scopedContextKeyService); this.disposeOnEditorActions.push(titleBarMenu, titleBarMenu.onDidChange(_ => this.update())); - fillInActions(titleBarMenu, { primary, secondary }); + fillInActions(titleBarMenu, this.resourceContext.get(), { primary, secondary }); } return { primary, secondary }; @@ -480,7 +480,7 @@ export abstract class TitleControl implements ITitleAreaControl { } // Fill in contributed actions - fillInActions(this.contextMenu, actions); + fillInActions(this.contextMenu, this.resourceContext.get(), actions); return actions; } diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index d9dae9e1403..20273dc58a3 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -53,7 +53,7 @@ export class PanelPart extends CompositePart implements IPanelService { partService, keybindingService, instantiationService, - (Registry.as(PanelExtensions.Panels)), + Registry.as(PanelExtensions.Panels), PanelPart.activePanelSettingsKey, 'panel', 'panel', diff --git a/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts b/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts index 2eaeb66a893..f632e3efc78 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickopen.contribution.ts @@ -128,30 +128,30 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ }); function navigateKeybinding(shift: boolean): IKeybindings { - if (shift) { - return { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, - secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_E, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab], - mac: { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, - secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab] - } - }; - } else { + if (!shift) { return { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, - secondary: [KeyMod.CtrlCmd | KeyCode.KEY_E, KeyMod.CtrlCmd | KeyCode.Tab], + secondary: [KeyMod.CtrlCmd | KeyCode.KEY_E, KeyMod.CtrlCmd | KeyCode.Tab, KeyMod.CtrlCmd | KeyCode.KEY_Q], mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, - secondary: [KeyMod.WinCtrl | KeyCode.Tab] + secondary: [KeyMod.WinCtrl | KeyCode.Tab, KeyMod.WinCtrl | KeyCode.KEY_Q] } }; } + + return { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_E, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Q], + mac: { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, + secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab, KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_Q] + } + }; } const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalQuickOpenAction, GlobalQuickOpenAction.ID, GlobalQuickOpenAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_E], mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, secondary: null } }), 'Go to File...'); -registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenNavigateNextAction, QuickOpenNavigateNextAction.ID, QuickOpenNavigateNextAction.LABEL, navigateKeybinding(false), condition), 'Navigate Next in Quick Open'); +registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenNavigateNextAction, QuickOpenNavigateNextAction.ID, QuickOpenNavigateNextAction.LABEL, navigateKeybinding(false), condition, KeybindingsRegistry.WEIGHT.workbenchContrib(50)), 'Navigate Next in Quick Open'); registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenNavigatePreviousAction, QuickOpenNavigatePreviousAction.ID, QuickOpenNavigatePreviousAction.LABEL, navigateKeybinding(true), condition, KeybindingsRegistry.WEIGHT.workbenchContrib(50)), 'Navigate Previous in Quick Open'); registry.registerWorkbenchAction(new SyncActionDescriptor(RemoveFromEditorHistoryAction, RemoveFromEditorHistoryAction.ID, RemoveFromEditorHistoryAction.LABEL), 'Remove From History'); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 63dfec32019..629f6f925dd 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -60,7 +60,7 @@ export class SidebarPart extends CompositePart implements ISidebar { partService, keybindingService, instantiationService, - (Registry.as(ViewletExtensions.Viewlets)), + Registry.as(ViewletExtensions.Viewlets), SidebarPart.activeViewletSettingsKey, 'sideBar', 'viewlet', diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index a927b9dc424..8433e64effe 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -335,7 +335,7 @@ export class WorkbenchShell { appender: new TelemetryAppenderClient(channel), commonProperties: resolveWorkbenchCommonProperties(this.storageService, commit, version), piiPaths: [this.environmentService.appRoot, this.environmentService.extensionsPath], - experiments: loadExperiments(this.storageService, this.configurationService) + experiments: loadExperiments(this.contextService, this.storageService, this.configurationService) }; const telemetryService = instantiationService.createInstance(TelemetryService, config); @@ -352,7 +352,7 @@ export class WorkbenchShell { disposables.add(telemetryService, errorTelemetry, listener, idleMonitor); } else { - NullTelemetryService._experiments = loadExperiments(this.storageService, this.configurationService); + NullTelemetryService._experiments = loadExperiments(this.contextService, this.storageService, this.configurationService); this.telemetryService = NullTelemetryService; } diff --git a/src/vs/workbench/electron-browser/workbench.main.ts b/src/vs/workbench/electron-browser/workbench.main.ts index 49bdb1848ea..bced534e400 100644 --- a/src/vs/workbench/electron-browser/workbench.main.ts +++ b/src/vs/workbench/electron-browser/workbench.main.ts @@ -106,4 +106,6 @@ import 'vs/workbench/electron-browser/main'; import 'vs/workbench/parts/themes/test/electron-browser/themes.test.contribution'; -import 'vs/workbench/parts/watermark/electron-browser/watermark'; \ No newline at end of file +import 'vs/workbench/parts/watermark/electron-browser/watermark'; + +import 'vs/workbench/parts/viewpicker/browser/viewpicker.contribution'; \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 734be88d8d2..c4a38749c2c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -504,8 +504,7 @@ export class Workbench implements IPartService { // Sidebar visibility this.sideBarHidden = this.storageService.getBoolean(Workbench.sidebarHiddenSettingKey, StorageScope.WORKSPACE, false); if (!this.contextService.getWorkspace()) { - // some first time users will see a sidebar; returning users will not see the sidebar - this.sideBarHidden = !this.telemetryService.getExperiments().showDefaultViewlet; + this.sideBarHidden = true; // we hide sidebar in single-file-mode } const viewletRegistry = Registry.as(ViewletExtensions.Viewlets); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index 76c1f387e6b..42c8d79555d 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -41,6 +41,7 @@ export interface IRenderValueOptions { preserveWhitespace?: boolean; showChanged?: boolean; maxValueLength?: number; + showHover?: boolean; } export function renderExpressionValue(expressionOrValue: debug.IExpression | string, container: HTMLElement, options: IRenderValueOptions): void { @@ -75,7 +76,9 @@ export function renderExpressionValue(expressionOrValue: debug.IExpression | str } else { container.textContent = value; } - container.title = value; + if (options.showHover) { + container.title = value; + } } export function renderVariable(tree: ITree, variable: Variable, data: IVariableTemplateData, showChanged: boolean): void { @@ -89,9 +92,9 @@ export function renderVariable(tree: ITree, variable: Variable, data: IVariableT renderExpressionValue(variable, data.value, { showChanged, maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET, - preserveWhitespace: false + preserveWhitespace: false, + showHover: true }); - data.value.title = variable.value; } else { data.value.textContent = ''; data.value.title = ''; @@ -958,7 +961,8 @@ export class WatchExpressionsRenderer implements IRenderer { renderExpressionValue(watchExpression, data.value, { showChanged: true, maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET, - preserveWhitespace: false + preserveWhitespace: false, + showHover: true }); data.name.title = watchExpression.type ? watchExpression.type : watchExpression.value; } diff --git a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts index ed7ab537ecf..e432d3a798d 100644 --- a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts @@ -220,7 +220,8 @@ export class ReplExpressionsRenderer implements IRenderer { private renderExpression(tree: ITree, expression: IExpression, templateData: IExpressionTemplateData): void { templateData.input.textContent = expression.name; renderExpressionValue(expression, templateData.value, { - preserveWhitespace: true + preserveWhitespace: true, + showHover: false }); if (expression.hasChildren) { templateData.annotation.className = 'annotation octicon octicon-info'; @@ -244,7 +245,8 @@ export class ReplExpressionsRenderer implements IRenderer { let result = this.handleANSIOutput(output.value); if (typeof result === 'string') { renderExpressionValue(result, templateData.value, { - preserveWhitespace: true + preserveWhitespace: true, + showHover: false }); } else { templateData.value.appendChild(result); @@ -263,7 +265,8 @@ export class ReplExpressionsRenderer implements IRenderer { // value renderExpressionValue(output.value, templateData.value, { - preserveWhitespace: true + preserveWhitespace: true, + showHover: false }); // annotation if any diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 3ee2478993a..88ee16f2642 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -507,7 +507,7 @@ export class FileController extends DefaultController { getAnchor: () => anchor, getActions: () => { return this.state.actionProvider.getSecondaryActions(tree, stat).then(actions => { - fillInActions(this.contributedContextMenu, actions); + fillInActions(this.contributedContextMenu, stat.resource, actions); return actions; }); }, @@ -959,4 +959,4 @@ export class FileDragAndDrop implements IDragAndDrop { promise.done(null, errors.onUnexpectedError); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/markers/browser/markersTreeController.ts b/src/vs/workbench/parts/markers/browser/markersTreeController.ts index 6b246e37528..eb1ef5ce954 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeController.ts @@ -156,4 +156,4 @@ export class Controller extends treedefaults.DefaultController { } return null; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/preferences/browser/media/preferences.css b/src/vs/workbench/parts/preferences/browser/media/preferences.css index 50ebe870c5b..78ed9a1496e 100644 --- a/src/vs/workbench/parts/preferences/browser/media/preferences.css +++ b/src/vs/workbench/parts/preferences/browser/media/preferences.css @@ -21,3 +21,15 @@ .monaco-editor.hc-black .copy-preferences-light-bulb { background: url('lightbulb-dark.svg') center center no-repeat; } + +.monaco-editor .floating-click-widget { + background: rgb(179,255,179); + padding: 10px; + border-radius: 5px; + cursor: pointer; +} + +.monaco-editor.vs-dark .floating-click-widget, +.monaco-editor.hc-black .floating-click-widget { + background: rgb(21,97,21); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts index 4a24709dd34..f1b61d1c23f 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesWidgets.ts @@ -3,9 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as DOM from 'vs/base/browser/dom'; import { Widget } from 'vs/base/browser/ui/widget'; -import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import Event, { Emitter } from 'vs/base/common/event'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; export class CopyPreferenceWidget extends Widget implements IOverlayWidget { @@ -88,3 +90,49 @@ export class CopyPreferenceWidget extends Widget implements IOverlayWidget { } } } + +export class FloatingClickWidget extends Widget implements IOverlayWidget { + + private _domNode: HTMLElement; + + private _onClick: Emitter = this._register(new Emitter()); + public onClick: Event = this._onClick.event; + + constructor(private editor: ICodeEditor, private label: string, private keyBindingAction: string, + @IKeybindingService keybindingService: IKeybindingService + ) { + super(); + if (keyBindingAction) { + let keybinding = keybindingService.lookupKeybindings(keyBindingAction); + if (keybinding.length > 0) { + this.label += ' (' + keybindingService.getLabelFor(keybinding[0]) + ')'; + } + } + } + + public render() { + this._domNode = DOM.$('.floating-click-widget'); + DOM.append(this._domNode, DOM.$('')).textContent = this.label; + this.onclick(this._domNode, e => this._onClick.fire()); + this.editor.addOverlayWidget(this); + } + + public dispose(): void { + this.editor.removeOverlayWidget(this); + super.dispose(); + } + + public getId(): string { + return 'editor.overlayWidget.floatingClickWidget'; + } + + public getDomNode(): HTMLElement { + return this._domNode; + } + + public getPosition(): IOverlayWidgetPosition { + return { + preference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER + }; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/viewpicker/browser/viewPickerHandler.ts b/src/vs/workbench/parts/viewpicker/browser/viewPickerHandler.ts new file mode 100644 index 00000000000..7b6f7ca1439 --- /dev/null +++ b/src/vs/workbench/parts/viewpicker/browser/viewPickerHandler.ts @@ -0,0 +1,217 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { TPromise } from 'vs/base/common/winjs.base'; +import nls = require('vs/nls'); +import { Registry } from 'vs/platform/platform'; +import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; +import errors = require('vs/base/common/errors'); +import strings = require('vs/base/common/strings'); +import scorer = require('vs/base/common/scorer'); +import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration } from 'vs/base/parts/quickopen/common/quickOpen'; +import { QuickOpenModel, QuickOpenEntryGroup, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; +import { QuickOpenHandler, QuickOpenAction } from 'vs/workbench/browser/quickopen'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IOutputService, Extensions as OutputExtensions, IOutputChannelRegistry, OUTPUT_PANEL_ID } from 'vs/workbench/parts/output/common/output'; +import { ITerminalService, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { Action } from 'vs/base/common/actions'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; + +export const VIEW_PICKER_PREFIX = 'view '; + +export class ViewEntry extends QuickOpenEntryGroup { + + constructor( + private label: string, + private category: string, + private open: () => void + ) { + super(); + } + + public getLabel(): string { + return this.label; + } + + public getCategory(): string { + return this.category; + } + + public getAriaLabel(): string { + return nls.localize('entryAriaLabel', "{0}, view picker", this.getLabel()); + } + + public run(mode: Mode, context: IEntryRunContext): boolean { + if (mode === Mode.OPEN) { + return this.runOpen(context); + } + + return super.run(mode, context); + } + + private runOpen(context: IEntryRunContext): boolean { + setTimeout(() => { + this.open(); + }, 0); + + return true; + } +} + +export class ViewPickerHandler extends QuickOpenHandler { + + constructor( + @IViewletService private viewletService: IViewletService, + @IOutputService private outputService: IOutputService, + @ITerminalService private terminalService: ITerminalService, + @IPanelService private panelService: IPanelService + ) { + super(); + } + + public getResults(searchValue: string): TPromise { + searchValue = searchValue.trim(); + const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); + + const viewEntries = this.getViewEntries(); + + const entries = viewEntries.filter(e => { + if (!searchValue) { + return true; + } + + if (!scorer.matches(e.getLabel(), normalizedSearchValueLowercase) && !scorer.matches(e.getCategory(), normalizedSearchValueLowercase)) { + return false; + } + + const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(e, searchValue); + e.setHighlights(labelHighlights, descriptionHighlights); + + return true; + }); + + return TPromise.as(new QuickOpenModel(entries)); + } + + private getViewEntries(): ViewEntry[] { + const viewEntries: ViewEntry[] = []; + + // Viewlets + const viewlets = this.viewletService.getViewlets(); + viewlets.forEach((viewlet, index) => { + const viewsCategory = nls.localize('views', "Views"); + const entry = new ViewEntry(viewlet.name, viewsCategory, () => this.viewletService.openViewlet(viewlet.id, true).done(null, errors.onUnexpectedError)); + viewEntries.push(entry); + + if (index === 0) { + entry.setGroupLabel(viewsCategory); + } + }); + + const terminals = this.terminalService.terminalInstances; + + // Panels + const panels = Registry.as(PanelExtensions.Panels).getPanels().filter(p => { + if (p.id === OUTPUT_PANEL_ID) { + return false; // since we already show output channels below + } + + if (p.id === TERMINAL_PANEL_ID && terminals.length > 0) { + return false; // since we already show terminal instances below + } + + return true; + }); + panels.forEach((panel, index) => { + const panelsCategory = nls.localize('panels', "Panels"); + const entry = new ViewEntry(panel.name, panelsCategory, () => this.panelService.openPanel(panel.id, true).done(null, errors.onUnexpectedError)); + if (index === 0) { + entry.setShowBorder(true); + entry.setGroupLabel(panelsCategory); + } + + viewEntries.push(entry); + }); + + // Terminals + terminals.forEach((terminal, index) => { + const terminalsCategory = nls.localize('terminals', "Terminal"); + const entry = new ViewEntry(nls.localize('terminalTitle', "{0}: {1}", index + 1, terminal.title), terminalsCategory, () => { + this.terminalService.showPanel(true).done(() => { + this.terminalService.setActiveInstance(terminal); + }, errors.onUnexpectedError); + }); + + if (index === 0) { + entry.setShowBorder(true); + entry.setGroupLabel(terminalsCategory); + } + + viewEntries.push(entry); + }); + + // Output Channels + const channels = Registry.as(OutputExtensions.OutputChannels).getChannels(); + channels.forEach((channel, index) => { + const outputCategory = nls.localize('channels', "Output"); + const entry = new ViewEntry(channel.label, outputCategory, () => this.outputService.getChannel(channel.id).show().done(null, errors.onUnexpectedError)); + + if (index === 0) { + entry.setShowBorder(true); + entry.setGroupLabel(outputCategory); + } + + viewEntries.push(entry); + }); + + return viewEntries; + } + + public getAutoFocus(searchValue: string, quickNavigateConfiguration: IQuickNavigateConfiguration): IAutoFocus { + return { + autoFocusFirstEntry: !!searchValue || !!quickNavigateConfiguration + }; + } +} + +export class OpenViewPickerAction extends QuickOpenAction { + + public static ID = 'workbench.action.openView'; + public static LABEL = nls.localize('openView', "Open View"); + + constructor( + id: string, + label: string, + @IQuickOpenService quickOpenService: IQuickOpenService + ) { + super(id, label, VIEW_PICKER_PREFIX, quickOpenService); + } +} + +export class QuickOpenViewPickerAction extends Action { + + public static ID = 'workbench.action.quickOpenView'; + public static LABEL = nls.localize('quickOpenView', "Quick Open View"); + + constructor( + id: string, + label: string, + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IKeybindingService private keybindingService: IKeybindingService + ) { + super(id, label); + } + + public run(): TPromise { + const keys = this.keybindingService.lookupKeybindings(this.id); + + this.quickOpenService.show(VIEW_PICKER_PREFIX, { quickNavigateConfiguration: { keybindings: keys } }); + + return TPromise.as(true); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/viewpicker/browser/viewpicker.contribution.ts b/src/vs/workbench/parts/viewpicker/browser/viewpicker.contribution.ts new file mode 100644 index 00000000000..9ab715cc1a1 --- /dev/null +++ b/src/vs/workbench/parts/viewpicker/browser/viewpicker.contribution.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Registry } from 'vs/platform/platform'; +import nls = require('vs/nls'); +import { QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions } from 'vs/workbench/browser/quickopen'; +import { VIEW_PICKER_PREFIX, OpenViewPickerAction, QuickOpenViewPickerAction } from 'vs/workbench/parts/viewpicker/browser/viewPickerHandler'; +import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; + +Registry.as(QuickOpenExtensions.Quickopen).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/viewpicker/browser/viewPickerHandler', + 'ViewPickerHandler', + VIEW_PICKER_PREFIX, + [ + { + prefix: VIEW_PICKER_PREFIX, + needsEditor: false, + description: nls.localize('viewPickerDescription', "Open View") + } + ] + ) +); + +const registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(OpenViewPickerAction, OpenViewPickerAction.ID, OpenViewPickerAction.LABEL), 'Open View'); +registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenViewPickerAction, QuickOpenViewPickerAction.ID, QuickOpenViewPickerAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_Q, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_Q }, linux: { primary: null } }), 'Quick Open View'); diff --git a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts index 77bfe67ca95..0b0b06db0f0 100644 --- a/src/vs/workbench/parts/watermark/electron-browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/electron-browser/watermark.ts @@ -99,7 +99,7 @@ const openGlobalKeybindings: WatermarkEntry = { ids: [OpenGlobalKeybindingsAction.ID] }; -const firstSessionEntries = [ +const newUserEntries = [ showCommands, selectTheme, selectKeymap, @@ -158,9 +158,8 @@ export class WatermarkContribution implements IWorkbenchContribution { const box = $(watermark) .div({ 'class': 'watermark-box' }); const folder = !!this.contextService.getWorkspace(); - const firstSession = this.telemetryService.getExperiments().showFirstSessionWatermark && - !this.storageService.get('telemetry.lastSessionDate'); - const selected = (folder ? folderEntries : firstSession ? firstSessionEntries : noFolderEntries) + const newUser = this.telemetryService.getExperiments().showNewUserWatermark; + const selected = (newUser ? newUserEntries : (folder ? folderEntries : noFolderEntries)) .filter(entry => !('mac' in entry) || entry.mac === isMacintosh); const update = () => { const builder = $(box);