From 84ddf6e169ebab26752af4c534f67281d1fe0850 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 11:10:38 +0200 Subject: [PATCH 001/126] extensions input & part --- .../extensions/common/extensionsInput.ts | 25 +++++++ .../electron-browser/extensionsPart.ts | 74 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/vs/workbench/parts/extensions/common/extensionsInput.ts create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts new file mode 100644 index 00000000000..f538138fe6b --- /dev/null +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { localize } from 'vs/nls'; +import { EventEmitter } from 'vs/base/common/eventEmitter'; +import { IEditorInput } from 'vs/platform/editor/common/editor'; + +export class ExtensionsInput extends EventEmitter implements IEditorInput { + + getId(): string { + return 'workbench.extensions.input'; + } + + getName(): string { + return localize('extension', 'Extensions'); + } + + matches(other: any): boolean { + return other instanceof ExtensionsInput; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts new file mode 100644 index 00000000000..a925f01d274 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * 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/text!./webview.html'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { Dimension, Builder } from 'vs/base/browser/builder'; +import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { Position } from 'vs/platform/editor/common/editor'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; + +export class ExtensionsPart extends BaseEditor { + + static ID: string = 'workbench.editor.extensionsPart'; + + private domNode: HTMLDivElement; + + constructor( + @ITelemetryService telemetryService: ITelemetryService + ) { + super(ExtensionsPart.ID, telemetryService); + } + + createEditor(parent: Builder): void { + this.domNode = document.createElement('div'); + parent.getHTMLElement().appendChild(this.domNode); + } + + setVisible(visible: boolean, position?: Position): TPromise { + return super.setVisible(visible, position); + } + + layout(dimension: Dimension): void { + // TODO + } + + focus(): void { + // TODO + } + + setInput(input: EditorInput, options: EditorOptions): TPromise { + if (this.input === input) { + return TPromise.as(undefined); + } + + // this._model = undefined; + // this._modelChangeSubscription.dispose(); + + if (!(input instanceof ExtensionsInput)) { + return TPromise.wrapError('Invalid input'); + } + + // return this._editorService.resolveEditorModel({ resource: (input).getResource() }).then(model => { + // if (model instanceof BaseTextEditorModel) { + // this._model = model.textEditorModel; + // } + // if (!this._model) { + // return TPromise.wrapError(localize('html.voidInput', "Invalid editor input.")); + // } + // this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this.webview.contents = this._model.getLinesContent()); + // this.webview.contents = this._model.getLinesContent(); + // return super.setInput(input, options); + // }); + } + + dispose(): void { + super.dispose(); + } +} From 879d0a4c1f8e6cfa9274370c7aea419038462019 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 15:31:16 +0200 Subject: [PATCH 002/126] map inputs to editor --- .../parts/extensions/common/extensionsInput.ts | 10 +++++++--- .../electron-browser/extensions.contribution.ts | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index f538138fe6b..9bd89bcee50 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -6,10 +6,10 @@ 'use strict'; import { localize } from 'vs/nls'; -import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IEditorInput } from 'vs/platform/editor/common/editor'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { EditorInput } from 'vs/workbench/common/editor'; -export class ExtensionsInput extends EventEmitter implements IEditorInput { +export class ExtensionsInput extends EditorInput { getId(): string { return 'workbench.extensions.input'; @@ -22,4 +22,8 @@ export class ExtensionsInput extends EventEmitter implements IEditorInput { matches(other: any): boolean { return other instanceof ExtensionsInput; } + + resolve(refresh?: boolean): TPromise { + return TPromise.as(null); + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 626715f89f2..0ae3cdc6688 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/extensions'; +import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/platform'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar'; @@ -13,6 +14,10 @@ import { GalleryService } from 'vs/workbench/parts/extensions/common/vsoGalleryS import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; +import { ExtensionsPart } from 'vs/workbench/parts/extensions/electron-browser/extensionsPart'; registerSingleton(IGalleryService, GalleryService); @@ -23,4 +28,14 @@ Registry.as(StatusbarExtensions.Statusbar) .registerStatusbarItem(new StatusbarItemDescriptor(ExtensionsStatusbarItem, StatusbarAlignment.LEFT,10000)); Registry.as(OutputExtensions.OutputChannels) - .registerChannel(ExtensionsLabel); \ No newline at end of file + .registerChannel(ExtensionsLabel); + +const editorDescriptor = new EditorDescriptor( + ExtensionsPart.ID, + localize('extensions', "Extensions"), + 'vs/workbench/parts/extensions/electron-browser/extensionsPart', + 'ExtensionsPart' +); + +Registry.as(EditorExtensions.Editors) + .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); From a4ddc14f87d4d9943228f346abcaf76c920a4f03 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 15:37:52 +0200 Subject: [PATCH 003/126] remove bad import --- .../parts/extensions/electron-browser/extensionsPart.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index a925f01d274..5c0762473b6 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -5,7 +5,6 @@ 'use strict'; -import 'vs/text!./webview.html'; import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; From 72ed29aa6aa625f5ca0ef727d4364ac5c77cebcf Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 15:38:02 +0200 Subject: [PATCH 004/126] bring back global toolbar area --- .../parts/activitybar/activitybarPart.ts | 116 +++++++++--------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index cd5f4a3c516..ec8640eda1e 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -12,7 +12,7 @@ import {Builder, $} from 'vs/base/browser/builder'; import {Action} from 'vs/base/common/actions'; import errors = require('vs/base/common/errors'); import {ActionsOrientation, ActionBar, IActionItem} from 'vs/base/browser/ui/actionbar/actionbar'; -import {ToolBar} from 'vs/base/browser/ui/toolbar/toolbar'; +import {CONTEXT, ToolBar} from 'vs/base/browser/ui/toolbar/toolbar'; import {Registry} from 'vs/platform/platform'; import {CompositeEvent, EventType} from 'vs/workbench/common/events'; import {ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions} from 'vs/workbench/browser/viewlet'; @@ -27,6 +27,10 @@ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiat import {IMessageService} from 'vs/platform/message/common/message'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService'; +import {Scope, IActionBarRegistry, Extensions as ActionBarExtensions, prepareActions} from 'vs/workbench/browser/actionBarRegistry'; +import Severity from 'vs/base/common/severity'; +import {IAction} from 'vs/base/common/actions'; +import events = require('vs/base/common/events'); export class ActivitybarPart extends Part implements IActivityService { public serviceId = IActivityService; @@ -107,7 +111,7 @@ export class ActivitybarPart extends Part implements IActivityService { this.createViewletSwitcher($result.clone()); // Bottom Toolbar with action items for global actions - // this.createGlobalToolBarArea($result.clone()); // not used currently + this.createGlobalToolBarArea($result.clone()); // not used currently return $result; } @@ -152,75 +156,75 @@ export class ActivitybarPart extends Part implements IActivityService { this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); } - // private createGlobalToolBarArea(div: Builder): void { + private createGlobalToolBarArea(div: Builder): void { - // // Global action bar is on the bottom - // this.globalToolBar = new ToolBar(div.getHTMLElement(), this.contextMenuService, { - // actionItemProvider: (action: Action) => this.activityActionItems[action.id], - // orientation: ActionsOrientation.VERTICAL - // }); - // this.globalToolBar.getContainer().addClass('global'); + // Global action bar is on the bottom + this.globalToolBar = new ToolBar(div.getHTMLElement(), this.contextMenuService, { + actionItemProvider: (action: Action) => this.activityActionItems[action.id], + orientation: ActionsOrientation.VERTICAL + }); + this.globalToolBar.getContainer().addClass('global'); - // this.globalToolBar.actionRunner.addListener(events.EventType.RUN, (e: any) => { + this.globalToolBar.actionRunner.addListener(events.EventType.RUN, (e: any) => { - // // Check for Error - // if (e.error && !errors.isPromiseCanceledError(e.error)) { - // this.messageService.show(Severity.Error, e.error); - // } + // Check for Error + if (e.error && !errors.isPromiseCanceledError(e.error)) { + this.messageService.show(Severity.Error, e.error); + } - // // Log in telemetry - // if (this.telemetryService) { - // this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'activityBar' }); - // } - // }); + // Log in telemetry + if (this.telemetryService) { + this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'activityBar' }); + } + }); - // // Build Global Actions in correct order - // let primaryActions = this.getGlobalActions(true); - // let secondaryActions = this.getGlobalActions(false); + // Build Global Actions in correct order + let primaryActions = this.getGlobalActions(true); + let secondaryActions = this.getGlobalActions(false); - // if (primaryActions.length + secondaryActions.length > 0) { - // this.globalToolBar.getContainer().addClass('position-bottom'); - // } + if (primaryActions.length + secondaryActions.length > 0) { + this.globalToolBar.getContainer().addClass('position-bottom'); + } - // // Add to global action bar - // this.globalToolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions))(); - // } + // Add to global action bar + this.globalToolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions))(); + } - // private getGlobalActions(primary: boolean): IAction[] { - // let actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); + private getGlobalActions(primary: boolean): IAction[] { + let actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); - // // Collect actions from actionbar contributor - // let actions: IAction[]; - // if (primary) { - // actions = actionBarRegistry.getActionBarActionsForContext(Scope.GLOBAL, CONTEXT); - // } else { - // actions = actionBarRegistry.getSecondaryActionBarActionsForContext(Scope.GLOBAL, CONTEXT); - // } + // Collect actions from actionbar contributor + let actions: IAction[]; + if (primary) { + actions = actionBarRegistry.getActionBarActionsForContext(Scope.GLOBAL, CONTEXT); + } else { + actions = actionBarRegistry.getSecondaryActionBarActionsForContext(Scope.GLOBAL, CONTEXT); + } - // return actions.map((action: Action) => { - // if (primary) { - // let keybinding: string = null; - // let keys = this.keybindingService.lookupKeybindings(action.id).map(k => this.keybindingService.getLabelFor(k)); - // if (keys && keys.length) { - // keybinding = keys[0]; - // } + return actions.map((action: Action) => { + if (primary) { + let keybinding: string = null; + let keys = this.keybindingService.lookupKeybindings(action.id).map(k => this.keybindingService.getLabelFor(k)); + if (keys && keys.length) { + keybinding = keys[0]; + } - // let actionItem = actionBarRegistry.getActionItemForContext(Scope.GLOBAL, CONTEXT, action); + let actionItem = actionBarRegistry.getActionItemForContext(Scope.GLOBAL, CONTEXT, action); - // if (!actionItem) { - // actionItem = new ActivityActionItem(action, action.label, keybinding); - // } + if (!actionItem) { + actionItem = new ActivityActionItem(action, action.label, keybinding); + } - // if (actionItem instanceof ActivityActionItem) { - // ( actionItem).keybinding = keybinding; - // } + if (actionItem instanceof ActivityActionItem) { + ( actionItem).keybinding = keybinding; + } - // this.activityActionItems[action.id] = actionItem; - // } + this.activityActionItems[action.id] = actionItem; + } - // return action; - // }); - // } + return action; + }); + } public dispose(): void { if (this.viewletSwitcherBar) { From 7a923737372e753e00234fbbec8a1b7f890df243 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 16:06:48 +0200 Subject: [PATCH 005/126] manage extensions global action --- .../extensions.contribution.ts | 5 +++ .../electron-browser/extensionsActions.ts | 35 +++++++++++++++++-- .../electron-browser/media/extensions.css | 9 +++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 0ae3cdc6688..ab84fbad8ca 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -18,6 +18,8 @@ import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } fro import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { ExtensionsPart } from 'vs/workbench/parts/extensions/electron-browser/extensionsPart'; +import { GlobalExtensionsActionContributor } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; +import { IActionBarRegistry, Scope as ActionBarScope, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; registerSingleton(IGalleryService, GalleryService); @@ -39,3 +41,6 @@ const editorDescriptor = new EditorDescriptor( Registry.as(EditorExtensions.Editors) .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); + +Registry.as(ActionBarExtensions.Actionbar) + .registerActionBarContributor(ActionBarScope.GLOBAL, GlobalExtensionsActionContributor); \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index d42b46abd3a..b56a7bd731b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -5,7 +5,7 @@ import nls = require('vs/nls'); import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { Action } from 'vs/base/common/actions'; +import { IAction, Action } from 'vs/base/common/actions'; import { assign } from 'vs/base/common/objects'; import Severity from 'vs/base/common/severity'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -15,6 +15,8 @@ import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { IExtensionsService, IExtension } from 'vs/workbench/parts/extensions/common/extensions'; import { extensionEquals, getTelemetryData } from 'vs/workbench/parts/extensions/common/extensionsUtil'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; +import { CONTEXT as ToolbarContext } from 'vs/base/browser/ui/toolbar/toolbar'; const CloseAction = new Action('action.close', nls.localize('close', "Close")); @@ -204,7 +206,36 @@ export class UninstallAction extends Action { private reportTelemetry(extension: IExtension, success: boolean) { const data = assign(getTelemetryData(extension), { success }); - + this.telemetryService.publicLog('extensionGallery:uninstall', data); } } + +class ManageExtensionsAction extends Action { + + constructor() { + super('extensions.manage', nls.localize('openExtensions', "Manage Extensions"), 'manage-extensions-action'); + } + + run(): TPromise { + console.log('yeah'); + return null; + } +} + +export class GlobalExtensionsActionContributor extends ActionBarContributor { + + constructor(@IInstantiationService protected instantiationService: IInstantiationService) { + super(); + } + + public hasActions(context:any):boolean { + return context === ToolbarContext; + } + + public getActions(context:any): IAction[] { + return [ + this.instantiationService.createInstance(ManageExtensionsAction) + ]; + } +} \ No newline at end of file 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 a11a194e46a..90968970ee4 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -195,4 +195,13 @@ 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); animation: move-background 0.5s linear infinite; +} + +/* Global action */ + +.manage-extensions-action { + background: url('extensions-status.svg'); + background-size: 22px; + background-repeat: no-repeat; + background-position: 50% !important; } \ No newline at end of file From 7377739c9dfbf17b9f9e9fb1ba7a8535d97f2751 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 16:16:18 +0200 Subject: [PATCH 006/126] open extensions part --- .../extensions/electron-browser/extensionsActions.ts | 9 +++++---- .../parts/extensions/electron-browser/extensionsPart.ts | 9 ++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index b56a7bd731b..7994608a218 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -17,6 +17,8 @@ import { extensionEquals, getTelemetryData } from 'vs/workbench/parts/extensions import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; import { CONTEXT as ToolbarContext } from 'vs/base/browser/ui/toolbar/toolbar'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; const CloseAction = new Action('action.close', nls.localize('close', "Close")); @@ -213,13 +215,12 @@ export class UninstallAction extends Action { class ManageExtensionsAction extends Action { - constructor() { + constructor(@IWorkbenchEditorService private editorService: IWorkbenchEditorService) { super('extensions.manage', nls.localize('openExtensions', "Manage Extensions"), 'manage-extensions-action'); } - run(): TPromise { - console.log('yeah'); - return null; + run(): TPromise { + return this.editorService.openEditor(new ExtensionsInput()); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 5c0762473b6..2a263d189d3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder } from 'vs/base/browser/builder'; +import { append, emmet as $ } from 'vs/base/browser/dom'; import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; @@ -17,7 +18,7 @@ export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; - private domNode: HTMLDivElement; + private domNode: HTMLElement; constructor( @ITelemetryService telemetryService: ITelemetryService @@ -26,8 +27,8 @@ export class ExtensionsPart extends BaseEditor { } createEditor(parent: Builder): void { - this.domNode = document.createElement('div'); - parent.getHTMLElement().appendChild(this.domNode); + this.domNode = append(parent.getHTMLElement(), $('.HELLO')); + this.domNode.textContent = 'HELLO'; } setVisible(visible: boolean, position?: Position): TPromise { @@ -54,6 +55,8 @@ export class ExtensionsPart extends BaseEditor { return TPromise.wrapError('Invalid input'); } + return TPromise.as(null); + // return this._editorService.resolveEditorModel({ resource: (input).getResource() }).then(model => { // if (model instanceof BaseTextEditorModel) { // this._model = model.textEditorModel; From 57a8e0b25f146a3fbe8c0e5bab887af87892ca70 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 16:43:03 +0200 Subject: [PATCH 007/126] fix setInput --- .../electron-browser/extensionsPart.ts | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 2a263d189d3..daf3229ed5b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -8,11 +8,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { append, emmet as $ } from 'vs/base/browser/dom'; -import { EditorOptions, EditorInput } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; export class ExtensionsPart extends BaseEditor { @@ -43,33 +41,6 @@ export class ExtensionsPart extends BaseEditor { // TODO } - setInput(input: EditorInput, options: EditorOptions): TPromise { - if (this.input === input) { - return TPromise.as(undefined); - } - - // this._model = undefined; - // this._modelChangeSubscription.dispose(); - - if (!(input instanceof ExtensionsInput)) { - return TPromise.wrapError('Invalid input'); - } - - return TPromise.as(null); - - // return this._editorService.resolveEditorModel({ resource: (input).getResource() }).then(model => { - // if (model instanceof BaseTextEditorModel) { - // this._model = model.textEditorModel; - // } - // if (!this._model) { - // return TPromise.wrapError(localize('html.voidInput', "Invalid editor input.")); - // } - // this._modelChangeSubscription = this._model.addListener2(EventType.ModelContentChanged2, () => this.webview.contents = this._model.getLinesContent()); - // this.webview.contents = this._model.getLinesContent(); - // return super.setInput(input, options); - // }); - } - dispose(): void { super.dispose(); } From f00eb2b1a0f323ed20be9dffed53ab699963fff6 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 17:55:02 +0200 Subject: [PATCH 008/126] add extensions input factory --- .../extensions/common/extensionsInput.ts | 8 +++++++- .../extensions.contribution.ts | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 9bd89bcee50..5d16fe3c841 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -11,8 +11,14 @@ import { EditorInput } from 'vs/workbench/common/editor'; export class ExtensionsInput extends EditorInput { + static get ID() { return 'workbench.extensions.input'; } + + constructor() { + super(); + } + getId(): string { - return 'workbench.extensions.input'; + return ExtensionsInput.ID; } getName(): string { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index ab84fbad8ca..fd87c9c38dd 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -14,12 +14,27 @@ import { GalleryService } from 'vs/workbench/parts/extensions/common/vsoGalleryS import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; -import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory } from 'vs/workbench/browser/parts/editor/baseEditor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { ExtensionsPart } from 'vs/workbench/parts/extensions/electron-browser/extensionsPart'; import { GlobalExtensionsActionContributor } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; import { IActionBarRegistry, Scope as ActionBarScope, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; +import { EditorInput } from 'vs/workbench/common/editor'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +class ExtensionsInputFactory implements IEditorInputFactory { + + constructor() {} + + public serialize(editorInput: EditorInput): string { + return ''; + } + + public deserialize(instantiationService: IInstantiationService, resourceRaw: string): EditorInput { + return instantiationService.createInstance(ExtensionsInput); + } +} registerSingleton(IGalleryService, GalleryService); @@ -32,6 +47,9 @@ Registry.as(StatusbarExtensions.Statusbar) Registry.as(OutputExtensions.OutputChannels) .registerChannel(ExtensionsLabel); +Registry.as(EditorExtensions.Editors) + .registerEditorInputFactory(ExtensionsInput.ID, ExtensionsInputFactory); + const editorDescriptor = new EditorDescriptor( ExtensionsPart.ID, localize('extensions', "Extensions"), From 3e8543d4fad80f0afc84886f6c0d6d7bd76077ca Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 17:58:32 +0200 Subject: [PATCH 009/126] render extensions manager --- .../parts/extensions/electron-browser/extensionsPart.ts | 4 ++-- .../parts/extensions/electron-browser/media/extensions.css | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index daf3229ed5b..d20d27fe824 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -25,8 +25,8 @@ export class ExtensionsPart extends BaseEditor { } createEditor(parent: Builder): void { - this.domNode = append(parent.getHTMLElement(), $('.HELLO')); - this.domNode.textContent = 'HELLO'; + const container = parent.getHTMLElement(); + this.domNode = append(container, $('.extension-manager')); } setVisible(visible: boolean, position?: Position): TPromise { 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 90968970ee4..c9bc0052ee1 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -141,6 +141,12 @@ transform: none; } +/* Extension Manager */ +.extension-manager { + width: 100%; + height: 100%; +} + /* Status bar */ .monaco-shell .extensions-statusbar { display: flex !important; From 2cab687f520f73f1d079183f6a0b574fcf3cc8fc Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 18:23:00 +0200 Subject: [PATCH 010/126] show extensions from gallery --- .../electron-browser/extensionsPart.ts | 88 ++++++++++++++++++- .../electron-browser/media/extensions.css | 34 +++++++ 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index d20d27fe824..595bd6acbfd 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -11,15 +11,86 @@ import { append, emmet as $ } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IRenderer, IDelegate } from 'vs/base/browser/ui/list/list'; +import { List } from 'vs/base/browser/ui/list/listWidget'; +import { IExtension, IGalleryService } from '../common/extensions'; + +interface ITemplateData { + container: HTMLElement; + extension: HTMLElement; + name: HTMLElement; +} + +enum ExtensionState { + Uninstalled, + Installed, + Outdated +} + +interface IExtensionEntry { + extension: IExtension; + state: ExtensionState; +} + +function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { + const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; + const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; + const diff = otherInstallCount - oneInstallCount; + + if (diff !== 0) { + return diff; + } + + return one.extension.displayName.localeCompare(other.extension.displayName); +} + +class Delegate implements IDelegate { + getHeight() { return 84; } + getTemplateId() { return 'extension'; } +} + +class Renderer implements IRenderer { + + constructor( + @IInstantiationService private instantiationService: IInstantiationService + ) {} + + get templateId() { return 'extension'; } + + renderTemplate(container: HTMLElement): ITemplateData { + const root = append(container, $('.extension-container')); + const extension = append(root, $('.extension')); + const name = append(extension, $('.span.name')); + + return { + container: root, + extension, + name + }; + } + + renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { + const extension = entry.extension; + data.name.textContent = extension.displayName; + } + + disposeTemplate(data: ITemplateData): void { + // TODO + } +} export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; + private list: List; private domNode: HTMLElement; constructor( - @ITelemetryService telemetryService: ITelemetryService + @ITelemetryService telemetryService: ITelemetryService, + @IGalleryService private galleryService: IGalleryService, + @IInstantiationService private instantiationService: IInstantiationService ) { super(ExtensionsPart.ID, telemetryService); } @@ -27,6 +98,19 @@ export class ExtensionsPart extends BaseEditor { createEditor(parent: Builder): void { const container = parent.getHTMLElement(); this.domNode = append(container, $('.extension-manager')); + const extensions = append(this.domNode, $('.extensions')); + this.list = new List(extensions, new Delegate(), [this.instantiationService.createInstance(Renderer)]); + + this.galleryService.query().then(({ firstPage }) => { + const entries = firstPage + .map(extension => ({ + extension, + state: ExtensionState.Installed + })) + .sort(extensionEntryCompare); + + this.list.splice(0, this.list.length, ...entries); + }); } setVisible(visible: boolean, position?: Position): TPromise { @@ -34,7 +118,7 @@ export class ExtensionsPart extends BaseEditor { } layout(dimension: Dimension): void { - // TODO + this.list.layout(dimension.height); } focus(): void { 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 c9bc0052ee1..0cad513ade2 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -143,9 +143,43 @@ /* Extension Manager */ .extension-manager { + background: #f1f1f1; width: 100%; height: 100%; } +.extension-manager > .extensions { + width: 100%; + max-width: 600px; + height: 100%; + margin: 0 auto; +} + +.extension-manager .monaco-list-row.selected { + background-color: inherit; + color: inherit; +} + +.extension-manager .monaco-list-row:hover { + background-color: inherit; +} + +.extension-manager .extension-container { + width: 100%; + height: 100%; +} + +.extension-manager .extension-container > .extension { + margin: 10px 20px 10px 10px; + width: calc(100% - 30px); + height: calc(100% - 20px); + background-color: white; + box-shadow: 2px 2px 5px rgba(0,0,0,.1); +} + +.extension-manager .extension-container > .extension:hover { + box-shadow: 2px 2px 5px rgba(0,0,0,.25); +} + /* Status bar */ .monaco-shell .extensions-statusbar { From 1cd8a93739e210ad4f1a5e3221fccca34b5c6f7c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 18:43:04 +0200 Subject: [PATCH 011/126] better extension rendering --- src/vs/base/browser/dom.ts | 5 +-- .../parts/extensions/common/extensions.ts | 1 + .../extensions/common/vsoGalleryService.ts | 3 +- .../electron-browser/extensionsPart.ts | 28 +++++++++++++--- .../electron-browser/media/extensions.css | 33 +++++++++++++++++++ 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 4964d28c457..8724453cc1c 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -931,7 +931,7 @@ export function append(parent: HTMLElement, child: T): T { const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((.([\w\-]+))*)/; // Similar to builder, but much more lightweight -export function emmet(description: string): HTMLElement { +export function emmet(description: string): T { let match = SELECTOR_REGEX.exec(description); if (!match) { @@ -939,6 +939,7 @@ export function emmet(description: string): HTMLElement { } let result = document.createElement(match[1] || 'div'); + if (match[3]) { result.id = match[3]; } @@ -946,7 +947,7 @@ export function emmet(description: string): HTMLElement { result.className = match[4].replace(/\./g, ' ').trim(); } - return result; + return result as T; } export function show(...elements: HTMLElement[]): void { diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index 1bd12d9efb6..52318b3c29d 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -25,6 +25,7 @@ export interface IGalleryVersion { date: string; manifestUrl: string; downloadUrl: string; + iconUrl: string; downloadHeaders: { [key: string]: string; }; } diff --git a/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts b/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts index 011e772147c..7cda5718ab9 100644 --- a/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts +++ b/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts @@ -166,7 +166,8 @@ function toExtension(galleryExtension: IGalleryExtension, extensionsGalleryUrl: date: v.lastUpdated, downloadHeaders, downloadUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.VSIXPackage?install=true`, - manifestUrl: `${ v.assetUri }/Microsoft.VisualStudio.Code.Manifest` + manifestUrl: `${ v.assetUri }/Microsoft.VisualStudio.Code.Manifest`, + iconUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Icons.Default` })); return { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 595bd6acbfd..b3d534d26d3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -5,6 +5,7 @@ 'use strict'; +import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { append, emmet as $ } from 'vs/base/browser/dom'; @@ -19,7 +20,11 @@ import { IExtension, IGalleryService } from '../common/extensions'; interface ITemplateData { container: HTMLElement; extension: HTMLElement; + icon: HTMLImageElement; name: HTMLElement; + version: HTMLElement; + author: HTMLElement; + description: HTMLElement; } enum ExtensionState { @@ -46,7 +51,7 @@ function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): nu } class Delegate implements IDelegate { - getHeight() { return 84; } + getHeight() { return 90; } // 74 getTemplateId() { return 'extension'; } } @@ -61,18 +66,31 @@ class Renderer implements IRenderer { renderTemplate(container: HTMLElement): ITemplateData { const root = append(container, $('.extension-container')); const extension = append(root, $('.extension')); - const name = append(extension, $('.span.name')); + const icon = append(extension, $('img.icon')); + const body = append(extension, $('.body')); + const title = append(body, $('.title')); + const subtitle = append(body, $('.subtitle')); + const name = append(title, $('span.name')); + const version = append(subtitle, $('span.version')); + const author = append(subtitle, $('span.author')); + const description = append(body, $('.description')); return { - container: root, - extension, - name + container: root, extension, icon, + name, version, author, description }; } renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { const extension = entry.extension; + const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; + const version = extension.galleryInformation.versions[0]; + + data.icon.src = version.iconUrl; data.name.textContent = extension.displayName; + data.version.textContent = ` ${ extension.version }`; + data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; + data.description.textContent = extension.description; } disposeTemplate(data: ITemplateData): void { 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 0cad513ade2..8dafa463847 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -180,6 +180,39 @@ box-shadow: 2px 2px 5px rgba(0,0,0,.25); } +.extension-manager .extension { + display: flex; +} + +.extension-manager .extension > .icon { + box-sizing: border-box; + width: 70px; + height: 70px; + padding: 8px; +} + +.extension-manager .extension > .body { + flex: 1; + padding: 8px; +} + +.extension-manager .extension > .body > .title > .name { + font-weight: bold; +} + +.extension-manager .extension > .body > .subtitle { + font-size: 90%; +} + +.extension-manager .extension > .body > .subtitle > .author { + font-style: italic; +} + +.extension-manager .extension > .body > .description { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} /* Status bar */ .monaco-shell .extensions-statusbar { From 1fd206140f465c7f24799892508453666ef2f5e0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 18:52:01 +0200 Subject: [PATCH 012/126] input box --- .../electron-browser/extensionsPart.ts | 9 +++++--- .../electron-browser/media/extensions.css | 21 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index b3d534d26d3..ed3b616abf5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -103,7 +103,6 @@ export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; private list: List; - private domNode: HTMLElement; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -115,8 +114,12 @@ export class ExtensionsPart extends BaseEditor { createEditor(parent: Builder): void { const container = parent.getHTMLElement(); - this.domNode = append(container, $('.extension-manager')); - const extensions = append(this.domNode, $('.extensions')); + + const root = append(container, $('.extension-manager')); + const search = append(root, $('.search')); + /*const searchBox =*/ append(search, $('input.search-box')); + + const extensions = append(root, $('.extensions')); this.list = new List(extensions, new Delegate(), [this.instantiationService.createInstance(Renderer)]); this.galleryService.query().then(({ firstPage }) => { 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 8dafa463847..58a9e19264c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -142,18 +142,37 @@ } /* Extension Manager */ + .extension-manager { background: #f1f1f1; width: 100%; height: 100%; } + +.extension-manager > .search, .extension-manager > .extensions { width: 100%; max-width: 600px; - height: 100%; margin: 0 auto; } +.extension-manager > .search { + box-sizing: border-box; + padding: 10px; +} + +.extension-manager > .search > .search-box { + margin: 10px 0; + width: calc(100% - 28px); /* TODO: HACK */ + padding: 6px 8px; + font-size: 16px; + border: 1px solid gainsboro; +} + +.extension-manager > .extensions { + height: 100%; +} + .extension-manager .monaco-list-row.selected { background-color: inherit; color: inherit; From b6b4319a7257f926f99eb9dccadd66bf089b8713 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Apr 2016 18:59:38 +0200 Subject: [PATCH 013/126] query extensions --- .../electron-browser/extensionsPart.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index ed3b616abf5..43a37f64ec0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; +import { Delayer } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { append, emmet as $ } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -117,7 +118,28 @@ export class ExtensionsPart extends BaseEditor { const root = append(container, $('.extension-manager')); const search = append(root, $('.search')); - /*const searchBox =*/ append(search, $('input.search-box')); + const searchBox = append(search, $('input.search-box')); + + const delayer = new Delayer(500); + + // TODO: HACK + searchBox.oninput = event => { + delayer.trigger(() => { + + this.galleryService.query({ text: searchBox.value }).then(({ firstPage }) => { + const entries = firstPage + .map(extension => ({ + extension, + state: ExtensionState.Installed + })) + .sort(extensionEntryCompare); + + this.list.splice(0, this.list.length, ...entries); + }); + + return null; + }); + }; const extensions = append(root, $('.extensions')); this.list = new List(extensions, new Delegate(), [this.instantiationService.createInstance(Renderer)]); From c4de585cc6766d3f27c7c1d67ea3ec26e402bfb3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Apr 2016 12:06:51 +0200 Subject: [PATCH 014/126] wip: paged list --- src/vs/base/browser/ui/list/listPaging.ts | 99 +++++++++++++++++++ .../electron-browser/extensionsPart.ts | 92 ++++++++++------- .../electron-browser/media/extensions.css | 6 ++ 3 files changed, 160 insertions(+), 37 deletions(-) create mode 100644 src/vs/base/browser/ui/list/listPaging.ts diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts new file mode 100644 index 00000000000..bd81493b3db --- /dev/null +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -0,0 +1,99 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./list'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDelegate, IRenderer } from './list'; +import { List } from './listWidget'; +import { PagedModel } from 'vs/base/common/paging'; + +export interface IPagedRenderer extends IRenderer { + renderPlaceholder(index: number, templateData: TTemplateData): void; +} + +export interface ITemplateData { + data: T; + disposable: IDisposable; +} + +export class PagedDelegate implements IDelegate { + + constructor(private delegate: IDelegate) { + // noop + } + + getHeight(element: number): number { + // TODO + return this.delegate.getHeight(null); + } + + getTemplateId(element: number): string { + // TODO + return this.delegate.getTemplateId(null); + } +} + +export class PagedRenderer implements IRenderer> { + + private _model: PagedModel; + set model(model: PagedModel) { this._model = model; } + get templateId(): string { return this.renderer.templateId; } + + constructor(private renderer: IPagedRenderer) { + // noop + } + + renderTemplate(container: HTMLElement): ITemplateData { + const data = this.renderer.renderTemplate(container); + return { data, disposable: { dispose: () => {} } }; + } + + renderElement(index: number, _: number, data: ITemplateData): void { + data.disposable.dispose(); + + if (!this._model) { + return; + } + + if (this._model.isResolved(index)) { + return this.renderer.renderElement(this._model.get(index), index, data.data); + } + + const promise = this._model.resolve(index); + data.disposable = { dispose: () => promise.cancel() }; + + this.renderer.renderPlaceholder(index, data.data); + promise.done(entry => this.renderer.renderElement(entry, index, data.data)); + } + + disposeTemplate(data: ITemplateData): void { + data.disposable.dispose(); + data.disposable = null; + this.renderer.disposeTemplate(data.data); + data.data = null; + } +} + +// TODO work on this +export class PagedList extends List { + + private _model: PagedModel; + + constructor( + container: HTMLElement, + delegate: IDelegate, + renderers: IPagedRenderer[] + ) { + super( + container, + new PagedDelegate(delegate), + renderers.map(r => new PagedRenderer(r)) + ); + } + + set model(model: PagedModel) { + this._model = model; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 43a37f64ec0..6d981d351ac 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -9,17 +9,19 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { Delayer } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; -import { append, emmet as $ } from 'vs/base/browser/dom'; +import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IRenderer, IDelegate } from 'vs/base/browser/ui/list/list'; +import { IDelegate } from 'vs/base/browser/ui/list/list'; +import { IPagedRenderer, PagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IExtension, IGalleryService } from '../common/extensions'; +import { PagedModel, mapPager, IPager } from 'vs/base/common/paging'; interface ITemplateData { - container: HTMLElement; + root: HTMLElement; extension: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -39,24 +41,24 @@ interface IExtensionEntry { state: ExtensionState; } -function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { - const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; - const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; - const diff = otherInstallCount - oneInstallCount; +// function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { +// const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; +// const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; +// const diff = otherInstallCount - oneInstallCount; - if (diff !== 0) { - return diff; - } +// if (diff !== 0) { +// return diff; +// } - return one.extension.displayName.localeCompare(other.extension.displayName); -} +// return one.extension.displayName.localeCompare(other.extension.displayName); +// } class Delegate implements IDelegate { getHeight() { return 90; } // 74 getTemplateId() { return 'extension'; } } -class Renderer implements IRenderer { +class Renderer implements IPagedRenderer { constructor( @IInstantiationService private instantiationService: IInstantiationService @@ -77,16 +79,27 @@ class Renderer implements IRenderer { const description = append(body, $('.description')); return { - container: root, extension, icon, + root, extension, icon, name, version, author, description }; } + renderPlaceholder(index: number, data: ITemplateData): void { + addClass(data.extension, 'loading'); + data.icon.style.display = 'none'; + data.name.textContent = ''; + data.version.textContent = ''; + data.author.textContent = ''; + data.description.textContent = ''; + } + renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { const extension = entry.extension; const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; const version = extension.galleryInformation.versions[0]; + removeClass(data.extension, 'loading'); + data.icon.style.display = 'block'; data.icon.src = version.iconUrl; data.name.textContent = extension.displayName; data.version.textContent = ` ${ extension.version }`; @@ -103,7 +116,7 @@ export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; - private list: List; + private list: List; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -122,38 +135,43 @@ export class ExtensionsPart extends BaseEditor { const delayer = new Delayer(500); + + const onResults = (result: IPager) => { + // const entries = firstPage + // .map() + // .sort(extensionEntryCompare); + + const model = new PagedModel(mapPager(result, extension => ({ + extension, + state: ExtensionState.Installed + }))); + + pagedRenderer.model = model; + + const foo = []; + for (let i = 0; i < model.length; i++) { + foo.push(i); + } + + this.list.splice(0, this.list.length, ...foo); + }; + // TODO: HACK searchBox.oninput = event => { delayer.trigger(() => { - - this.galleryService.query({ text: searchBox.value }).then(({ firstPage }) => { - const entries = firstPage - .map(extension => ({ - extension, - state: ExtensionState.Installed - })) - .sort(extensionEntryCompare); - - this.list.splice(0, this.list.length, ...entries); - }); - + this.galleryService.query({ text: searchBox.value }).then(onResults); return null; }); }; const extensions = append(root, $('.extensions')); - this.list = new List(extensions, new Delegate(), [this.instantiationService.createInstance(Renderer)]); - this.galleryService.query().then(({ firstPage }) => { - const entries = firstPage - .map(extension => ({ - extension, - state: ExtensionState.Installed - })) - .sort(extensionEntryCompare); + const renderer = this.instantiationService.createInstance(Renderer); + const pagedRenderer = new PagedRenderer(renderer); - this.list.splice(0, this.list.length, ...entries); - }); + this.list = new List(extensions, new Delegate(), [pagedRenderer]); + + this.galleryService.query().then(onResults); } setVisible(visible: boolean, position?: Position): TPromise { 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 58a9e19264c..08aa8689eb3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -203,6 +203,12 @@ display: flex; } +.extension-manager .extension.loading { + background-image: url('loading.svg'); + background-position: center center; + background-repeat: no-repeat; +} + .extension-manager .extension > .icon { box-sizing: border-box; width: 70px; From f39e6738a9f4d5cb77f7bc35119b0fc2204ed075 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Apr 2016 15:28:17 +0200 Subject: [PATCH 015/126] arrays.range --- src/vs/base/common/arrays.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index b068d41dba8..639e8e23ff3 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -195,3 +195,13 @@ export function commonPrefixLength(one: T[], other: T[], equals: (a: T, b: T) export function flatten(arr: T[][]): T[] { return arr.reduce((r, v) => r.concat(v), []); } + +export function range(to: number, from = 0): number[] { + const result = []; + + for (let i = from; i < to; i++) { + result.push(i); + } + + return result; +} \ No newline at end of file From bd5872acab883f4c335d1c23e264140331854977 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Apr 2016 15:38:16 +0200 Subject: [PATCH 016/126] paged list --- src/vs/base/browser/ui/list/listPaging.ts | 58 +++++---------- .../electron-browser/extensionsPart.ts | 74 ++++++++----------- 2 files changed, 49 insertions(+), 83 deletions(-) diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index bd81493b3db..4b66fc02bdd 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -5,6 +5,7 @@ import 'vs/css!./list'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { range } from 'vs/base/common/arrays'; import { IDelegate, IRenderer } from './list'; import { List } from './listWidget'; import { PagedModel } from 'vs/base/common/paging'; @@ -18,32 +19,14 @@ export interface ITemplateData { disposable: IDisposable; } -export class PagedDelegate implements IDelegate { +class PagedRenderer implements IRenderer> { - constructor(private delegate: IDelegate) { - // noop - } - - getHeight(element: number): number { - // TODO - return this.delegate.getHeight(null); - } - - getTemplateId(element: number): string { - // TODO - return this.delegate.getTemplateId(null); - } -} - -export class PagedRenderer implements IRenderer> { - - private _model: PagedModel; - set model(model: PagedModel) { this._model = model; } get templateId(): string { return this.renderer.templateId; } - constructor(private renderer: IPagedRenderer) { - // noop - } + constructor( + private renderer: IPagedRenderer, + private modelProvider: () => PagedModel + ) {} renderTemplate(container: HTMLElement): ITemplateData { const data = this.renderer.renderTemplate(container); @@ -53,15 +36,13 @@ export class PagedRenderer implements IRenderer): void { data.disposable.dispose(); - if (!this._model) { - return; + const model = this.modelProvider(); + + if (model.isResolved(index)) { + return this.renderer.renderElement(model.get(index), index, data.data); } - if (this._model.isResolved(index)) { - return this.renderer.renderElement(this._model.get(index), index, data.data); - } - - const promise = this._model.resolve(index); + const promise = model.resolve(index); data.disposable = { dispose: () => promise.cancel() }; this.renderer.renderPlaceholder(index, data.data); @@ -76,24 +57,25 @@ export class PagedRenderer implements IRenderer extends List { private _model: PagedModel; constructor( container: HTMLElement, - delegate: IDelegate, - renderers: IPagedRenderer[] + delegate: IDelegate, + renderers: IPagedRenderer[] ) { - super( - container, - new PagedDelegate(delegate), - renderers.map(r => new PagedRenderer(r)) - ); + const pagedRenderers = renderers.map(r => new PagedRenderer>(r, () => this.model)); + super(container, delegate, pagedRenderers); + } + + get model(): PagedModel { + return this._model; } set model(model: PagedModel) { this._model = model; + this.splice(0, this.length, ...range(model.length)); } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 6d981d351ac..57736139406 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { Delayer } from 'vs/base/common/async'; +import { ThrottledDelayer } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -15,10 +15,9 @@ import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; -import { IPagedRenderer, PagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { List } from 'vs/base/browser/ui/list/listWidget'; +import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, IGalleryService } from '../common/extensions'; -import { PagedModel, mapPager, IPager } from 'vs/base/common/paging'; +import { PagedModel, mapPager } from 'vs/base/common/paging'; interface ITemplateData { root: HTMLElement; @@ -54,7 +53,7 @@ interface IExtensionEntry { // } class Delegate implements IDelegate { - getHeight() { return 90; } // 74 + getHeight() { return 90; } getTemplateId() { return 'extension'; } } @@ -116,7 +115,9 @@ export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; - private list: List; + private list: PagedList; + private searchDelayer: ThrottledDelayer; + private searchBox: HTMLInputElement; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -124,58 +125,31 @@ export class ExtensionsPart extends BaseEditor { @IInstantiationService private instantiationService: IInstantiationService ) { super(ExtensionsPart.ID, telemetryService); + this.searchDelayer = new ThrottledDelayer(500); } createEditor(parent: Builder): void { const container = parent.getHTMLElement(); - const root = append(container, $('.extension-manager')); const search = append(root, $('.search')); - const searchBox = append(search, $('input.search-box')); - - const delayer = new Delayer(500); - - - const onResults = (result: IPager) => { - // const entries = firstPage - // .map() - // .sort(extensionEntryCompare); - - const model = new PagedModel(mapPager(result, extension => ({ - extension, - state: ExtensionState.Installed - }))); - - pagedRenderer.model = model; - - const foo = []; - for (let i = 0; i < model.length; i++) { - foo.push(i); - } - - this.list.splice(0, this.list.length, ...foo); - }; - - // TODO: HACK - searchBox.oninput = event => { - delayer.trigger(() => { - this.galleryService.query({ text: searchBox.value }).then(onResults); - return null; - }); - }; - + this.searchBox = append(search, $('input.search-box')); const extensions = append(root, $('.extensions')); + const delegate = new Delegate(); const renderer = this.instantiationService.createInstance(Renderer); - const pagedRenderer = new PagedRenderer(renderer); + this.list = new PagedList(extensions, delegate, [renderer]); - this.list = new List(extensions, new Delegate(), [pagedRenderer]); - - this.galleryService.query().then(onResults); + this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); } setVisible(visible: boolean, position?: Position): TPromise { - return super.setVisible(visible, position); + return super.setVisible(visible, position).then(() => { + + if (visible) { + this.searchBox.value = ''; + this.triggerSearch('', 0); + } + }); } layout(dimension: Dimension): void { @@ -186,6 +160,16 @@ export class ExtensionsPart extends BaseEditor { // TODO } + private triggerSearch(text: string = '', delay = 500): void { + this.searchDelayer.trigger(() => this.doSearch(text), delay); + } + + private doSearch(text: string = ''): TPromise { + return this.galleryService.query({ text }) + .then(result => new PagedModel(mapPager(result, extension => ({ extension, state: ExtensionState.Installed })))) + .then(model => this.list.model = model); + } + dispose(): void { super.dispose(); } From ff4ebddf6aba7773ab7cc23dcbbcb3b1d4d11b13 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Apr 2016 15:53:28 +0200 Subject: [PATCH 017/126] layout --- .../extensions/electron-browser/extensionsPart.ts | 10 +++++++--- .../extensions/electron-browser/media/extensions.css | 5 +---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 57736139406..11ca56c712d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -118,6 +118,7 @@ export class ExtensionsPart extends BaseEditor { private list: PagedList; private searchDelayer: ThrottledDelayer; private searchBox: HTMLInputElement; + private extensionsBox: HTMLElement; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -133,11 +134,11 @@ export class ExtensionsPart extends BaseEditor { const root = append(container, $('.extension-manager')); const search = append(root, $('.search')); this.searchBox = append(search, $('input.search-box')); - const extensions = append(root, $('.extensions')); + this.extensionsBox = append(root, $('.extensions')); const delegate = new Delegate(); const renderer = this.instantiationService.createInstance(Renderer); - this.list = new PagedList(extensions, delegate, [renderer]); + this.list = new PagedList(this.extensionsBox, delegate, [renderer]); this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); } @@ -153,7 +154,10 @@ export class ExtensionsPart extends BaseEditor { } layout(dimension: Dimension): void { - this.list.layout(dimension.height); + const height = dimension.height - 72; + + this.extensionsBox.style.height = `${ height }px`; + this.list.layout(height); } focus(): void { 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 08aa8689eb3..950b5f4961a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -159,6 +159,7 @@ .extension-manager > .search { box-sizing: border-box; padding: 10px; + height: 72px; } .extension-manager > .search > .search-box { @@ -169,10 +170,6 @@ border: 1px solid gainsboro; } -.extension-manager > .extensions { - height: 100%; -} - .extension-manager .monaco-list-row.selected { background-color: inherit; color: inherit; From c276394f563b822bd04701d01c2b54964b674f30 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 8 Apr 2016 16:12:31 +0200 Subject: [PATCH 018/126] search progress --- .../electron-browser/extensionsPart.ts | 20 +++++++++++++++---- .../electron-browser/media/extensions.css | 10 ++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 11ca56c712d..765c7c22a3d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { ThrottledDelayer } from 'vs/base/common/async'; +import { ThrottledDelayer, always } from 'vs/base/common/async'; import { Dimension, Builder } from 'vs/base/browser/builder'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -111,6 +111,13 @@ class Renderer implements IPagedRenderer { } } +const EmptyModel = new PagedModel({ + firstPage: [], + total: 0, + pageSize: 0, + getPage: null +}); + export class ExtensionsPart extends BaseEditor { static ID: string = 'workbench.editor.extensionsPart'; @@ -134,6 +141,7 @@ export class ExtensionsPart extends BaseEditor { const root = append(container, $('.extension-manager')); const search = append(root, $('.search')); this.searchBox = append(search, $('input.search-box')); + this.searchBox.placeholder = localize('searchExtensions', "Search Extensions"); this.extensionsBox = append(root, $('.extensions')); const delegate = new Delegate(); @@ -145,7 +153,6 @@ export class ExtensionsPart extends BaseEditor { setVisible(visible: boolean, position?: Position): TPromise { return super.setVisible(visible, position).then(() => { - if (visible) { this.searchBox.value = ''; this.triggerSearch('', 0); @@ -161,11 +168,16 @@ export class ExtensionsPart extends BaseEditor { } focus(): void { - // TODO + this.searchBox.focus(); } private triggerSearch(text: string = '', delay = 500): void { - this.searchDelayer.trigger(() => this.doSearch(text), delay); + this.list.model = EmptyModel; + + const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); + + addClass(this.extensionsBox, 'loading'); + always(promise, () => removeClass(this.extensionsBox, 'loading')); } private doSearch(text: string = ''): TPromise { 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 950b5f4961a..9e4b0cac4e0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -165,11 +165,17 @@ .extension-manager > .search > .search-box { margin: 10px 0; width: calc(100% - 28px); /* TODO: HACK */ - padding: 6px 8px; + padding: 10px 8px; font-size: 16px; border: 1px solid gainsboro; } +.extension-manager .extensions.loading { + background-image: url('loading.svg'); + background-position: top center; + background-repeat: no-repeat; +} + .extension-manager .monaco-list-row.selected { background-color: inherit; color: inherit; @@ -230,7 +236,7 @@ font-style: italic; } -.extension-manager .extension > .body > .description { +.extension-manager .extension > .body > div { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; From 7b14a9e58b418042b0dfb2176f5a03ecfb0024de Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Apr 2016 10:51:42 +0200 Subject: [PATCH 019/126] extensions part highlight --- src/vs/base/browser/ui/list/listPaging.ts | 26 +++- src/vs/base/browser/ui/list/listWidget.ts | 6 + .../electron-browser/extensionsPart.ts | 127 ++++++++++++++-- .../electron-browser/media/extensions.css | 101 ------------- .../electron-browser/media/extensions2.css | 142 ++++++++++++++++++ 5 files changed, 284 insertions(+), 118 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 4b66fc02bdd..0676a9e3ab2 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -6,9 +6,10 @@ import 'vs/css!./list'; import { IDisposable } from 'vs/base/common/lifecycle'; import { range } from 'vs/base/common/arrays'; -import { IDelegate, IRenderer } from './list'; +import { IDelegate, IRenderer, IFocusChangeEvent, ISelectionChangeEvent } from './list'; import { List } from './listWidget'; import { PagedModel } from 'vs/base/common/paging'; +import Event, { mapEvent } from 'vs/base/common/event'; export interface IPagedRenderer extends IRenderer { renderPlaceholder(index: number, templateData: TTemplateData): void; @@ -57,8 +58,9 @@ class PagedRenderer implements IRenderer extends List { +export class PagedList { + private list: List; private _model: PagedModel; constructor( @@ -67,7 +69,15 @@ export class PagedList extends List { renderers: IPagedRenderer[] ) { const pagedRenderers = renderers.map(r => new PagedRenderer>(r, () => this.model)); - super(container, delegate, pagedRenderers); + this.list = new List(container, delegate, pagedRenderers); + } + + get onFocusChange(): Event> { + return mapEvent(this.list.onFocusChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes })); + } + + get onSelectionChange(): Event> { + return mapEvent(this.list.onSelectionChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes })); } get model(): PagedModel { @@ -76,6 +86,14 @@ export class PagedList extends List { set model(model: PagedModel) { this._model = model; - this.splice(0, this.length, ...range(model.length)); + this.list.splice(0, this.list.length, ...range(model.length)); + } + + get scrollTop(): number { + return this.list.scrollTop; + } + + layout(height?: number): void { + this.list.layout(height); } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index d9555eec843..b2fc96e9f4f 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -130,6 +130,8 @@ class Controller implements IDisposable { } private onClick(e: IListMouseEvent) { + e.preventDefault(); + e.stopPropagation(); this.list.setSelection(e.index); } @@ -193,6 +195,10 @@ export class List implements IDisposable { return this.view.getScrollHeight(); } + get scrollTop(): number { + return this.view.getScrollTop(); + } + layout(height?: number): void { this.view.layout(height); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 765c7c22a3d..b1c59b09645 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -5,11 +5,13 @@ 'use strict'; +import 'vs/css!./media/extensions2'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { Dimension, Builder } from 'vs/base/browser/builder'; -import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { IDisposable, toDisposable, empty, dispose } from 'vs/base/common/lifecycle'; +import { Builder } from 'vs/base/browser/builder'; +import { append, emmet as $, addClass, removeClass, getDomNodePosition, addDisposableListener } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -17,9 +19,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, IGalleryService } from '../common/extensions'; +import { getExtensionId } from '../common/extensionsUtil'; import { PagedModel, mapPager } from 'vs/base/common/paging'; interface ITemplateData { + id: string; root: HTMLElement; extension: HTMLElement; icon: HTMLImageElement; @@ -59,9 +63,14 @@ class Delegate implements IDelegate { class Renderer implements IPagedRenderer { + private _templates: ITemplateData[]; + get templates(): ITemplateData[] { return this._templates; } + constructor( @IInstantiationService private instantiationService: IInstantiationService - ) {} + ) { + this._templates = []; + } get templateId() { return 'extension'; } @@ -76,15 +85,18 @@ class Renderer implements IPagedRenderer { const version = append(subtitle, $('span.version')); const author = append(subtitle, $('span.author')); const description = append(body, $('.description')); - - return { - root, extension, icon, + const result = { + id: null, root, extension, icon, name, version, author, description }; + + this._templates.push(result); + return result; } renderPlaceholder(index: number, data: ITemplateData): void { addClass(data.extension, 'loading'); + data.id = null; data.icon.style.display = 'none'; data.name.textContent = ''; data.version.textContent = ''; @@ -97,6 +109,7 @@ class Renderer implements IPagedRenderer { const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; const version = extension.galleryInformation.versions[0]; + data.id = getExtensionId(extension); removeClass(data.extension, 'loading'); data.icon.style.display = 'block'; data.icon.src = version.iconUrl; @@ -107,7 +120,11 @@ class Renderer implements IPagedRenderer { } disposeTemplate(data: ITemplateData): void { - // TODO + const index = this._templates.indexOf(data); + + if (index > -1) { + this._templates.splice(index, 1); + } } } @@ -124,8 +141,15 @@ export class ExtensionsPart extends BaseEditor { private list: PagedList; private searchDelayer: ThrottledDelayer; + private root: HTMLElement; private searchBox: HTMLInputElement; private extensionsBox: HTMLElement; + private overlay: HTMLElement; + + private _highlight: ITemplateData; + private highlightDisposable: IDisposable; + + private toDispose: IDisposable[]; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -134,37 +158,76 @@ export class ExtensionsPart extends BaseEditor { ) { super(ExtensionsPart.ID, telemetryService); this.searchDelayer = new ThrottledDelayer(500); + this._highlight = null; + this.highlightDisposable = empty; + this.toDispose = []; } createEditor(parent: Builder): void { const container = parent.getHTMLElement(); - const root = append(container, $('.extension-manager')); - const search = append(root, $('.search')); + this.root = append(container, $('.extension-manager')); + + this.toDispose.push(addDisposableListener(this.root, 'click', e => { + if (e.target === this.root && this.highlight) { + this.highlight = null; + } + })); + + const search = append(this.root, $('.search')); this.searchBox = append(search, $('input.search-box')); this.searchBox.placeholder = localize('searchExtensions', "Search Extensions"); - this.extensionsBox = append(root, $('.extensions')); + this.extensionsBox = append(this.root, $('.extensions')); const delegate = new Delegate(); const renderer = this.instantiationService.createInstance(Renderer); this.list = new PagedList(this.extensionsBox, delegate, [renderer]); + this.overlay = append(this.extensionsBox, $('.overlay')); + this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); + + this.list.onSelectionChange(({ elements }) => { + if (this.highlightDisposable) { + removeClass(this.overlay, 'animated'); + this.highlightDisposable.dispose(); + this.highlightDisposable = null; + } + + const [selected] = elements; + + if (!selected) { + return; + } + + const id = getExtensionId(selected.extension); + const [data] = renderer.templates.filter(t => t.id === id); + + if (!data) { + return; + } + + this.highlight = data; + }); } setVisible(visible: boolean, position?: Position): TPromise { return super.setVisible(visible, position).then(() => { if (visible) { + this.highlight = null; this.searchBox.value = ''; this.triggerSearch('', 0); } }); } - layout(dimension: Dimension): void { - const height = dimension.height - 72; - + layout({ height }): void { + height -= 72; this.extensionsBox.style.height = `${ height }px`; this.list.layout(height); + + if (this.highlight) { + this.overlay.style.height = this.extensionsBox.style.height; + } } focus(): void { @@ -186,7 +249,45 @@ export class ExtensionsPart extends BaseEditor { .then(model => this.list.model = model); } + private get highlight(): ITemplateData { + return this._highlight; + } + + private set highlight(data: ITemplateData) { + this._highlight = data; + + if (!data) { + removeClass(this.root, 'highlighted'); + this.highlightDisposable.dispose(); + return; + } + + const position = getDomNodePosition(data.root); + const rootPosition = getDomNodePosition(this.extensionsBox); + + removeClass(this.overlay, 'animated'); + + this.overlay.style.top = `${ position.top - rootPosition.top - this.list.scrollTop }px`; + this.overlay.style.height = `${ position.height }px`; + let _ = this.overlay.offsetHeight; _ = _; // trigger reflow + addClass(this.overlay, 'animated'); + this.overlay.style.top = '0'; + this.overlay.style.height = this.extensionsBox.style.height; + + const container = data.root.parentElement; + this.overlay.appendChild(data.root); + addClass(this.root, 'highlighted'); + + this.highlightDisposable = toDisposable(() => { + container.appendChild(data.root); + removeClass(this.overlay, 'animated'); + this.overlay.style.height = '0'; + }); + } + dispose(): void { + this._highlight = null; + this.toDispose = dispose(this.toDispose); super.dispose(); } } 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 9e4b0cac4e0..90968970ee4 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -141,107 +141,6 @@ transform: none; } -/* Extension Manager */ - -.extension-manager { - background: #f1f1f1; - width: 100%; - height: 100%; -} - -.extension-manager > .search, -.extension-manager > .extensions { - width: 100%; - max-width: 600px; - margin: 0 auto; -} - -.extension-manager > .search { - box-sizing: border-box; - padding: 10px; - height: 72px; -} - -.extension-manager > .search > .search-box { - margin: 10px 0; - width: calc(100% - 28px); /* TODO: HACK */ - padding: 10px 8px; - font-size: 16px; - border: 1px solid gainsboro; -} - -.extension-manager .extensions.loading { - background-image: url('loading.svg'); - background-position: top center; - background-repeat: no-repeat; -} - -.extension-manager .monaco-list-row.selected { - background-color: inherit; - color: inherit; -} - -.extension-manager .monaco-list-row:hover { - background-color: inherit; -} - -.extension-manager .extension-container { - width: 100%; - height: 100%; -} - -.extension-manager .extension-container > .extension { - margin: 10px 20px 10px 10px; - width: calc(100% - 30px); - height: calc(100% - 20px); - background-color: white; - box-shadow: 2px 2px 5px rgba(0,0,0,.1); -} - -.extension-manager .extension-container > .extension:hover { - box-shadow: 2px 2px 5px rgba(0,0,0,.25); -} - -.extension-manager .extension { - display: flex; -} - -.extension-manager .extension.loading { - background-image: url('loading.svg'); - background-position: center center; - background-repeat: no-repeat; -} - -.extension-manager .extension > .icon { - box-sizing: border-box; - width: 70px; - height: 70px; - padding: 8px; -} - -.extension-manager .extension > .body { - flex: 1; - padding: 8px; -} - -.extension-manager .extension > .body > .title > .name { - font-weight: bold; -} - -.extension-manager .extension > .body > .subtitle { - font-size: 90%; -} - -.extension-manager .extension > .body > .subtitle > .author { - font-style: italic; -} - -.extension-manager .extension > .body > div { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - /* Status bar */ .monaco-shell .extensions-statusbar { display: flex !important; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css new file mode 100644 index 00000000000..5fc2bfb2008 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css @@ -0,0 +1,142 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* Extension Manager */ + +.extension-manager { + position: relative; + background: #f1f1f1; + width: 100%; + height: 100%; +} + +.extension-manager.highlighted .monaco-list { + display: none; +} + +.extension-manager > .search, +.extension-manager > .extensions { + width: 100%; + max-width: 600px; + margin: 0 auto; +} + +.extension-manager > .search { + box-sizing: border-box; + padding: 10px; + height: 72px; +} + +.extension-manager > .search > .search-box { + margin: 10px 0; + width: calc(100% - 28px); /* TODO: HACK */ + padding: 10px 8px; + font-size: 16px; + border: 1px solid gainsboro; +} + +.extension-manager > .extensions { + position: relative; + overflow: hidden; +} + +.extension-manager .extensions.loading { + background-image: url('loading.svg'); + background-position: top center; + background-repeat: no-repeat; +} + +.extension-manager > .extensions > .overlay { + box-sizing: border-box; + position: absolute; + width: 100%; + left: 0; + padding: 0 20px 0 10px; +} + +.extension-manager > .extensions > .overlay.animated { + transition-property: top, height, padding; + transition-duration: 0.2s; + transition-timing-function: ease-out; +} + +.extension-manager .monaco-list-row.selected { + background-color: inherit; + color: inherit; +} + +.extension-manager .monaco-list-row:hover { + background-color: inherit; +} + +.extension-manager .extension-container { + width: 100%; + height: 100%; +} + +.extension-manager .extension-container > .extension { + margin: 10px 20px 10px 10px; + width: calc(100% - 30px); + height: calc(100% - 20px); +} + +.extension-manager .overlay .extension-container > .extension { + margin: 0; + width: 100%; + height: 100%; +} + +.extension-manager > .extensions > .overlay > .highlighted-extension, +.extension-manager .extension-container > .extension { + background-color: white; +} + +.extension-manager .monaco-list .extension-container > .extension { + box-shadow: 2px 2px 5px rgba(0,0,0,.1); +} + +.extension-manager .monaco-list .extension-container > .extension:hover { + box-shadow: 2px 2px 5px rgba(0,0,0,.25); +} + +.extension-manager .extension { + display: flex; +} + +.extension-manager .extension.loading { + background-image: url('loading.svg'); + background-position: center center; + background-repeat: no-repeat; +} + +.extension-manager .extension > .icon { + box-sizing: border-box; + width: 70px; + height: 70px; + padding: 8px; +} + +.extension-manager .extension > .body { + flex: 1; + padding: 8px; +} + +.extension-manager .extension > .body > .title > .name { + font-weight: bold; +} + +.extension-manager .extension > .body > .subtitle { + font-size: 90%; +} + +.extension-manager .extension > .body > .subtitle > .author { + font-style: italic; +} + +.extension-manager .extension > .body > div { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} \ No newline at end of file From 7f1033bcd8847b39f232f8783c7537cd45c86ac2 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Apr 2016 11:09:28 +0200 Subject: [PATCH 020/126] better animations --- .../electron-browser/extensionsPart.ts | 24 ++++++++++++------- .../electron-browser/media/extensions2.css | 20 ++++++++++++---- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index b1c59b09645..90c3ebc473d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -188,9 +188,9 @@ export class ExtensionsPart extends BaseEditor { this.list.onSelectionChange(({ elements }) => { if (this.highlightDisposable) { - removeClass(this.overlay, 'animated'); + removeClass(this.root, 'animated'); this.highlightDisposable.dispose(); - this.highlightDisposable = null; + this.highlightDisposable = empty; } const [selected] = elements; @@ -235,6 +235,7 @@ export class ExtensionsPart extends BaseEditor { } private triggerSearch(text: string = '', delay = 500): void { + this.highlight = null; this.list.model = EmptyModel; const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); @@ -259,28 +260,35 @@ export class ExtensionsPart extends BaseEditor { if (!data) { removeClass(this.root, 'highlighted'); this.highlightDisposable.dispose(); + this.highlightDisposable = empty; return; } const position = getDomNodePosition(data.root); const rootPosition = getDomNodePosition(this.extensionsBox); - removeClass(this.overlay, 'animated'); - this.overlay.style.top = `${ position.top - rootPosition.top - this.list.scrollTop }px`; this.overlay.style.height = `${ position.height }px`; - let _ = this.overlay.offsetHeight; _ = _; // trigger reflow - addClass(this.overlay, 'animated'); + let _ = this.overlay.offsetHeight; _++; // trigger reflow + + addClass(this.root, 'animated highlight-in'); this.overlay.style.top = '0'; this.overlay.style.height = this.extensionsBox.style.height; + // swap parents const container = data.root.parentElement; this.overlay.appendChild(data.root); - addClass(this.root, 'highlighted'); + + // transition end event + const listener = addDisposableListener(this.overlay, 'transitionend', e => { + listener.dispose(); + removeClass(this.root, 'animated'); + removeClass(this.root, 'highlight-in'); + addClass(this.root, 'highlighted'); + }); this.highlightDisposable = toDisposable(() => { container.appendChild(data.root); - removeClass(this.overlay, 'animated'); this.overlay.style.height = '0'; }); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css index 5fc2bfb2008..77461782ab5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css @@ -12,10 +12,6 @@ height: 100%; } -.extension-manager.highlighted .monaco-list { - display: none; -} - .extension-manager > .search, .extension-manager > .extensions { width: 100%; @@ -56,12 +52,26 @@ padding: 0 20px 0 10px; } -.extension-manager > .extensions > .overlay.animated { +.extension-manager.animated > .extensions > .overlay { transition-property: top, height, padding; transition-duration: 0.2s; transition-timing-function: ease-out; } +.extension-manager > .extensions > .monaco-list { + transition-property: opacity; + transition-duration: 0.2s; + transition-timing-function: ease-out; +} + +.extension-manager.highlight-in > .extensions > .monaco-list { + opacity: 0; +} + +.extension-manager.highlighted > .extensions > .monaco-list { + display: none; +} + .extension-manager .monaco-list-row.selected { background-color: inherit; color: inherit; From fcdf38f0d742b15cca7af416995c8153b1a7ec3f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Apr 2016 12:03:15 +0200 Subject: [PATCH 021/126] extension body --- .../electron-browser/extensionsPart.ts | 19 +++++++-------- .../electron-browser/media/extensions2.css | 23 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 90c3ebc473d..5465a41872a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -77,18 +77,19 @@ class Renderer implements IPagedRenderer { renderTemplate(container: HTMLElement): ITemplateData { const root = append(container, $('.extension-container')); const extension = append(root, $('.extension')); - const icon = append(extension, $('img.icon')); - const body = append(extension, $('.body')); - const title = append(body, $('.title')); - const subtitle = append(body, $('.subtitle')); + const header = append(extension, $('.header')); + const icon = append(header, $('img.icon')); + const details = append(header, $('.details')); + const title = append(details, $('.title')); + const subtitle = append(details, $('.subtitle')); const name = append(title, $('span.name')); const version = append(subtitle, $('span.version')); const author = append(subtitle, $('span.author')); - const description = append(body, $('.description')); - const result = { - id: null, root, extension, icon, - name, version, author, description - }; + const description = append(details, $('.description')); + const body = append(extension, $('.body')); + body.innerText = 'hello'; + + const result = { id: null, root, extension, icon, name, version, author, description }; this._templates.push(result); return result; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css index 77461782ab5..697fae15fb9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css @@ -90,6 +90,7 @@ margin: 10px 20px 10px 10px; width: calc(100% - 30px); height: calc(100% - 20px); + overflow: hidden; } .extension-manager .overlay .extension-container > .extension { @@ -111,41 +112,41 @@ box-shadow: 2px 2px 5px rgba(0,0,0,.25); } -.extension-manager .extension { - display: flex; -} - -.extension-manager .extension.loading { +.extension-manager .extension-container > .extension.loading { background-image: url('loading.svg'); background-position: center center; background-repeat: no-repeat; } -.extension-manager .extension > .icon { +.extension-manager .extension-container > .extension > .header { + display: flex; +} + +.extension-manager .extension-container > .extension > .header > .icon { box-sizing: border-box; width: 70px; height: 70px; padding: 8px; } -.extension-manager .extension > .body { +.extension-manager .extension-container > .extension > .header > .details { flex: 1; padding: 8px; } -.extension-manager .extension > .body > .title > .name { +.extension-manager .extension-container > .extension > .header > .details > .title > .name { font-weight: bold; } -.extension-manager .extension > .body > .subtitle { +.extension-manager .extension-container > .extension > .header > .details > .subtitle { font-size: 90%; } -.extension-manager .extension > .body > .subtitle > .author { +.extension-manager .extension-container > .extension > .header > .details > .subtitle > .author { font-style: italic; } -.extension-manager .extension > .body > div { +.extension-manager .extension-container > .extension > .header > .details > div { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; From e6d9e8d6d45c0b69d00d048a6cf276abacd39bfb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Apr 2016 12:38:11 +0200 Subject: [PATCH 022/126] readme display --- src/vs/base/node/request.ts | 17 ++++ .../parts/extensions/common/extensions.ts | 1 + .../extensions/common/vsoGalleryService.ts | 1 + .../electron-browser/extensionsPart.ts | 80 ++++++++++++++----- .../electron-browser/media/extensions2.css | 10 ++- 5 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts index 41b3aee353a..077c526ce59 100644 --- a/src/vs/base/node/request.ts +++ b/src/vs/base/node/request.ts @@ -86,6 +86,23 @@ export function download(filePath: string, opts: IRequestOptions): TPromise { + return request(opts).then(pair => new Promise((c, e) => { + if (!((pair.res.statusCode >= 200 && pair.res.statusCode < 300) || pair.res.statusCode === 1223)) { + return e('Server returned ' + pair.res.statusCode); + } + + if (pair.res.statusCode === 204) { + return c(null); + } + + let buffer: string[] = []; + pair.res.on('data', d => buffer.push(d)); + pair.res.on('end', () => c(buffer.join(''))); + pair.res.on('error', e); + })); +} + export function json(opts: IRequestOptions): TPromise { return request(opts).then(pair => new Promise((c, e) => { if (!((pair.res.statusCode >= 200 && pair.res.statusCode < 300) || pair.res.statusCode === 1223)) { diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index 52318b3c29d..ce72e233337 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -24,6 +24,7 @@ export interface IGalleryVersion { version: string; date: string; manifestUrl: string; + readmeUrl: string; downloadUrl: string; iconUrl: string; downloadHeaders: { [key: string]: string; }; diff --git a/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts b/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts index 7cda5718ab9..ba7d5b158f5 100644 --- a/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts +++ b/src/vs/workbench/parts/extensions/common/vsoGalleryService.ts @@ -167,6 +167,7 @@ function toExtension(galleryExtension: IGalleryExtension, extensionsGalleryUrl: downloadHeaders, downloadUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.VSIXPackage?install=true`, manifestUrl: `${ v.assetUri }/Microsoft.VisualStudio.Code.Manifest`, + readmeUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Content.Details`, iconUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Icons.Default` })); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 5465a41872a..8d8775c9803 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -9,6 +9,8 @@ import 'vs/css!./media/extensions2'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { ThrottledDelayer, always } from 'vs/base/common/async'; +import { marked } from 'vs/base/common/marked/marked'; +import { assign } from 'vs/base/common/objects'; import { IDisposable, toDisposable, empty, dispose } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; import { append, emmet as $, addClass, removeClass, getDomNodePosition, addDisposableListener } from 'vs/base/browser/dom'; @@ -21,16 +23,21 @@ import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, IGalleryService } from '../common/extensions'; import { getExtensionId } from '../common/extensionsUtil'; import { PagedModel, mapPager } from 'vs/base/common/paging'; +import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; +import { UserSettings } from 'vs/workbench/node/userSettings'; +import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; +import { getProxyAgent } from 'vs/base/node/proxy'; interface ITemplateData { - id: string; - root: HTMLElement; - extension: HTMLElement; + extension: IExtension; + container: HTMLElement; + element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; version: HTMLElement; author: HTMLElement; description: HTMLElement; + body: HTMLElement; } enum ExtensionState { @@ -74,10 +81,10 @@ class Renderer implements IPagedRenderer { get templateId() { return 'extension'; } - renderTemplate(container: HTMLElement): ITemplateData { - const root = append(container, $('.extension-container')); - const extension = append(root, $('.extension')); - const header = append(extension, $('.header')); + renderTemplate(root: HTMLElement): ITemplateData { + const container = append(root, $('.extension-container')); + const element = append(container, $('.extension')); + const header = append(element, $('.header')); const icon = append(header, $('img.icon')); const details = append(header, $('.details')); const title = append(details, $('.title')); @@ -86,23 +93,22 @@ class Renderer implements IPagedRenderer { const version = append(subtitle, $('span.version')); const author = append(subtitle, $('span.author')); const description = append(details, $('.description')); - const body = append(extension, $('.body')); - body.innerText = 'hello'; - - const result = { id: null, root, extension, icon, name, version, author, description }; + const body = append(element, $('.body')); + const result = { extension: null, container, element, icon, name, version, author, description, body }; this._templates.push(result); return result; } renderPlaceholder(index: number, data: ITemplateData): void { - addClass(data.extension, 'loading'); - data.id = null; + addClass(data.element, 'loading'); + data.extension = null; data.icon.style.display = 'none'; data.name.textContent = ''; data.version.textContent = ''; data.author.textContent = ''; data.description.textContent = ''; + data.body.textContent = ''; } renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { @@ -110,14 +116,15 @@ class Renderer implements IPagedRenderer { const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; const version = extension.galleryInformation.versions[0]; - data.id = getExtensionId(extension); - removeClass(data.extension, 'loading'); + data.extension = extension; + removeClass(data.element, 'loading'); data.icon.style.display = 'block'; data.icon.src = version.iconUrl; data.name.textContent = extension.displayName; data.version.textContent = ` ${ extension.version }`; data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; data.description.textContent = extension.description; + data.body.textContent = ''; } disposeTemplate(data: ITemplateData): void { @@ -155,6 +162,7 @@ export class ExtensionsPart extends BaseEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, @IGalleryService private galleryService: IGalleryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService ) { super(ExtensionsPart.ID, telemetryService); @@ -201,7 +209,7 @@ export class ExtensionsPart extends BaseEditor { } const id = getExtensionId(selected.extension); - const [data] = renderer.templates.filter(t => t.id === id); + const [data] = renderer.templates.filter(t => t.extension && getExtensionId(t.extension) === id); if (!data) { return; @@ -260,12 +268,14 @@ export class ExtensionsPart extends BaseEditor { if (!data) { removeClass(this.root, 'highlighted'); + removeClass(this.root, 'animated'); + removeClass(this.root, 'highlight-in'); this.highlightDisposable.dispose(); this.highlightDisposable = empty; return; } - const position = getDomNodePosition(data.root); + const position = getDomNodePosition(data.container); const rootPosition = getDomNodePosition(this.extensionsBox); this.overlay.style.top = `${ position.top - rootPosition.top - this.list.scrollTop }px`; @@ -277,8 +287,8 @@ export class ExtensionsPart extends BaseEditor { this.overlay.style.height = this.extensionsBox.style.height; // swap parents - const container = data.root.parentElement; - this.overlay.appendChild(data.root); + const container = data.container.parentElement; + this.overlay.appendChild(data.container); // transition end event const listener = addDisposableListener(this.overlay, 'transitionend', e => { @@ -288,9 +298,39 @@ export class ExtensionsPart extends BaseEditor { addClass(this.root, 'highlighted'); }); + const [version] = data.extension.galleryInformation.versions; + const headers = version.downloadHeaders; + + // TODO + this.request(version.readmeUrl) + .then(opts => assign(opts, { headers })) + .then(opts => downloadText(opts)) + .then(marked.parse) + .then(html => data.body.innerHTML = html); + + // set up disposable for later this.highlightDisposable = toDisposable(() => { - container.appendChild(data.root); + listener.dispose(); + container.appendChild(data.container); this.overlay.style.height = '0'; + data.body.innerHTML = ''; + }); + } + + // Helper for proxy business... shameful. + // This should be pushed down and not rely on the context service + private request(url: string): TPromise { + const settings = TPromise.join([ + UserSettings.getValue(this.contextService, 'http.proxy'), + UserSettings.getValue(this.contextService, 'http.proxyStrictSSL') + ]); + + return settings.then(settings => { + const proxyUrl: string = settings[0]; + const strictSSL: boolean = settings[1]; + const agent = getProxyAgent(url, { proxyUrl, strictSSL }); + + return { url, agent, strictSSL }; }); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css index 697fae15fb9..eb5b24278d1 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css @@ -15,7 +15,7 @@ .extension-manager > .search, .extension-manager > .extensions { width: 100%; - max-width: 600px; + max-width: 800px; margin: 0 auto; } @@ -91,6 +91,8 @@ width: calc(100% - 30px); height: calc(100% - 20px); overflow: hidden; + display: flex; + flex-direction: column; } .extension-manager .overlay .extension-container > .extension { @@ -150,4 +152,10 @@ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; +} + +.extension-manager .extension-container > .extension > .body { + flex: 1; + overflow-y: scroll; + padding: 10px; } \ No newline at end of file From 51fe52b6184202c9ab07c4743ad192639f17f2b4 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 12 Apr 2016 12:38:28 +0200 Subject: [PATCH 023/126] temporarily add extensions gallery --- product.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/product.json b/product.json index 5a7cf9cf28a..fd7bf24753c 100644 --- a/product.json +++ b/product.json @@ -6,5 +6,10 @@ "win32MutexName": "vscodeoss", "licenseUrl": "https://github.com/Microsoft/vscode/blob/master/LICENSE.txt", "darwinBundleIdentifier": "com.visualstudio.code.oss", - "welcomePage": "http://go.microsoft.com/fwlink/?LinkId=723048" + "welcomePage": "http://go.microsoft.com/fwlink/?LinkId=723048", + "extensionsGallery": { + "serviceUrl": "https://marketplace.visualstudio.com/_apis/public/gallery", + "cacheUrl": "https://vscode.blob.core.windows.net/gallery/index", + "itemUrl": "https://marketplace.visualstudio.com/items" + } } \ No newline at end of file From 12c85361f1afd13719575e157dda78730b9c5a8b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 18 Apr 2016 11:10:18 +0200 Subject: [PATCH 024/126] extension viewlet --- .../extensions.contribution.ts | 15 +++++- .../electron-browser/extensionsViewlet.ts | 52 +++++++++++++++++++ .../media/extensions-viewlet.css | 4 ++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index cb635b8610b..4fc87d2e02b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -22,6 +22,7 @@ import { GlobalExtensionsActionContributor } from 'vs/workbench/parts/extensions import { IActionBarRegistry, Scope as ActionBarScope, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; import { EditorInput } from 'vs/workbench/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; class ExtensionsInputFactory implements IEditorInputFactory { @@ -61,4 +62,16 @@ Registry.as(EditorExtensions.Editors) .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); Registry.as(ActionBarExtensions.Actionbar) - .registerActionBarContributor(ActionBarScope.GLOBAL, GlobalExtensionsActionContributor); \ No newline at end of file + .registerActionBarContributor(ActionBarScope.GLOBAL, GlobalExtensionsActionContributor); + +const viewletDescriptor = new ViewletDescriptor( + 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet', + 'ExtensionsViewlet', + 'workbench.viewlet.extensions', + localize('extensions', "Extensions"), + 'extensions', + 100 +); + +Registry.as(ViewletExtensions.Viewlets) + .registerViewlet(viewletDescriptor); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts new file mode 100644 index 00000000000..85344b4db29 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/extensions-viewlet'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Builder, Dimension } from 'vs/base/browser/builder'; +import { Viewlet } from 'vs/workbench/browser/viewlet'; +import { append, emmet as $ } from 'vs/base/browser/dom'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +export class ExtensionsViewlet extends Viewlet { + + static ID: string = 'workbench.viewlet.extensions'; + + private toDispose: IDisposable[]; + private root: HTMLElement; + + constructor(@ITelemetryService telemetryService: ITelemetryService) { + super(ExtensionsViewlet.ID, telemetryService); + this.toDispose = []; + } + + create(parent: Builder): TPromise { + super.create(parent); + + this.root = append(parent.getHTMLElement(), $('.extensions-viewlet')); + + return TPromise.as(null); + } + + setVisible(visible:boolean): TPromise { + return super.setVisible(visible); + } + + focus(): void { + super.focus(); + } + + layout(dimension: Dimension):void { + // noop + } + + dispose(): void { + this.toDispose = dispose(this.toDispose); + super.dispose(); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css new file mode 100644 index 00000000000..a4a092d8349 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css @@ -0,0 +1,4 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ From 730ad0719d2ac68874d87448c2537bd567990d8b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 18 Apr 2016 11:21:02 +0200 Subject: [PATCH 025/126] extensions viewlet: model --- .../electron-browser/extensionsList.ts | 122 ++++++++++++++++++ .../electron-browser/extensionsPart.ts | 114 +--------------- .../electron-browser/extensionsViewlet.ts | 66 +++++++++- .../media/extensions-viewlet.css | 12 ++ 4 files changed, 197 insertions(+), 117 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts new file mode 100644 index 00000000000..d6f7da44ee2 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -0,0 +1,122 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/extensions2'; +import { localize } from 'vs/nls'; +import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IDelegate } from 'vs/base/browser/ui/list/list'; +import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; +import { IExtension } from '../common/extensions'; + +export interface ITemplateData { + extension: IExtension; + container: HTMLElement; + element: HTMLElement; + icon: HTMLImageElement; + name: HTMLElement; + version: HTMLElement; + author: HTMLElement; + description: HTMLElement; + body: HTMLElement; +} + +export enum ExtensionState { + Uninstalled, + Installed, + Outdated +} + +export interface IExtensionEntry { + extension: IExtension; + state: ExtensionState; +} + +// function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { +// const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; +// const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; +// const diff = otherInstallCount - oneInstallCount; + +// if (diff !== 0) { +// return diff; +// } + +// return one.extension.displayName.localeCompare(other.extension.displayName); +// } + +export class Delegate implements IDelegate { + getHeight() { return 90; } + getTemplateId() { return 'extension'; } +} + +export class Renderer implements IPagedRenderer { + + private _templates: ITemplateData[]; + get templates(): ITemplateData[] { return this._templates; } + + constructor( + @IInstantiationService private instantiationService: IInstantiationService + ) { + this._templates = []; + } + + get templateId() { return 'extension'; } + + renderTemplate(root: HTMLElement): ITemplateData { + const container = append(root, $('.extension-container')); + const element = append(container, $('.extension')); + const header = append(element, $('.header')); + const icon = append(header, $('img.icon')); + const details = append(header, $('.details')); + const title = append(details, $('.title')); + const subtitle = append(details, $('.subtitle')); + const name = append(title, $('span.name')); + const version = append(subtitle, $('span.version')); + const author = append(subtitle, $('span.author')); + const description = append(details, $('.description')); + const body = append(element, $('.body')); + const result = { extension: null, container, element, icon, name, version, author, description, body }; + + this._templates.push(result); + return result; + } + + renderPlaceholder(index: number, data: ITemplateData): void { + addClass(data.element, 'loading'); + data.extension = null; + data.icon.style.display = 'none'; + data.name.textContent = ''; + data.version.textContent = ''; + data.author.textContent = ''; + data.description.textContent = ''; + data.body.textContent = ''; + } + + renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { + const extension = entry.extension; + const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; + const version = extension.galleryInformation.versions[0]; + + data.extension = extension; + removeClass(data.element, 'loading'); + data.icon.style.display = 'block'; + data.icon.src = version.iconUrl; + data.name.textContent = extension.displayName; + data.version.textContent = ` ${ extension.version }`; + data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; + data.description.textContent = extension.description; + data.body.textContent = ''; + } + + disposeTemplate(data: ITemplateData): void { + const index = this._templates.indexOf(data); + + if (index > -1) { + this._templates.splice(index, 1); + } + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 8d8775c9803..7b9221d7043 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -18,123 +18,15 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IDelegate } from 'vs/base/browser/ui/list/list'; -import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; -import { IExtension, IGalleryService } from '../common/extensions'; +import { PagedList } from 'vs/base/browser/ui/list/listPaging'; +import { IGalleryService } from '../common/extensions'; import { getExtensionId } from '../common/extensionsUtil'; import { PagedModel, mapPager } from 'vs/base/common/paging'; import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { UserSettings } from 'vs/workbench/node/userSettings'; import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; import { getProxyAgent } from 'vs/base/node/proxy'; - -interface ITemplateData { - extension: IExtension; - container: HTMLElement; - element: HTMLElement; - icon: HTMLImageElement; - name: HTMLElement; - version: HTMLElement; - author: HTMLElement; - description: HTMLElement; - body: HTMLElement; -} - -enum ExtensionState { - Uninstalled, - Installed, - Outdated -} - -interface IExtensionEntry { - extension: IExtension; - state: ExtensionState; -} - -// function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { -// const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; -// const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; -// const diff = otherInstallCount - oneInstallCount; - -// if (diff !== 0) { -// return diff; -// } - -// return one.extension.displayName.localeCompare(other.extension.displayName); -// } - -class Delegate implements IDelegate { - getHeight() { return 90; } - getTemplateId() { return 'extension'; } -} - -class Renderer implements IPagedRenderer { - - private _templates: ITemplateData[]; - get templates(): ITemplateData[] { return this._templates; } - - constructor( - @IInstantiationService private instantiationService: IInstantiationService - ) { - this._templates = []; - } - - get templateId() { return 'extension'; } - - renderTemplate(root: HTMLElement): ITemplateData { - const container = append(root, $('.extension-container')); - const element = append(container, $('.extension')); - const header = append(element, $('.header')); - const icon = append(header, $('img.icon')); - const details = append(header, $('.details')); - const title = append(details, $('.title')); - const subtitle = append(details, $('.subtitle')); - const name = append(title, $('span.name')); - const version = append(subtitle, $('span.version')); - const author = append(subtitle, $('span.author')); - const description = append(details, $('.description')); - const body = append(element, $('.body')); - const result = { extension: null, container, element, icon, name, version, author, description, body }; - - this._templates.push(result); - return result; - } - - renderPlaceholder(index: number, data: ITemplateData): void { - addClass(data.element, 'loading'); - data.extension = null; - data.icon.style.display = 'none'; - data.name.textContent = ''; - data.version.textContent = ''; - data.author.textContent = ''; - data.description.textContent = ''; - data.body.textContent = ''; - } - - renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { - const extension = entry.extension; - const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; - const version = extension.galleryInformation.versions[0]; - - data.extension = extension; - removeClass(data.element, 'loading'); - data.icon.style.display = 'block'; - data.icon.src = version.iconUrl; - data.name.textContent = extension.displayName; - data.version.textContent = ` ${ extension.version }`; - data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; - data.description.textContent = extension.description; - data.body.textContent = ''; - } - - disposeTemplate(data: ITemplateData): void { - const index = this._templates.indexOf(data); - - if (index > -1) { - this._templates.splice(index, 1); - } - } -} +import { IExtensionEntry, ITemplateData, Delegate, Renderer, ExtensionState } from './extensionsList'; const EmptyModel = new PagedModel({ firstPage: [], diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 85344b4db29..546792f30f9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -6,43 +6,97 @@ 'use strict'; import 'vs/css!./media/extensions-viewlet'; +import { localize } from 'vs/nls'; +import { ThrottledDelayer, always } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { Viewlet } from 'vs/workbench/browser/viewlet'; -import { append, emmet as $ } from 'vs/base/browser/dom'; +import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { PagedModel, mapPager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { PagedList } from 'vs/base/browser/ui/list/listPaging'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IExtensionEntry, Delegate, Renderer, ExtensionState } from './extensionsList'; +import { IGalleryService } from '../common/extensions'; + +const EmptyModel = new PagedModel({ + firstPage: [], + total: 0, + pageSize: 0, + getPage: null +}); export class ExtensionsViewlet extends Viewlet { static ID: string = 'workbench.viewlet.extensions'; private toDispose: IDisposable[]; + private searchDelayer: ThrottledDelayer; private root: HTMLElement; + private searchBox: HTMLInputElement; + private extensionsBox: HTMLElement; + private list: PagedList; - constructor(@ITelemetryService telemetryService: ITelemetryService) { + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IGalleryService private galleryService: IGalleryService, + @IInstantiationService private instantiationService: IInstantiationService + ) { super(ExtensionsViewlet.ID, telemetryService); + this.searchDelayer = new ThrottledDelayer(500); this.toDispose = []; } create(parent: Builder): TPromise { super.create(parent); + parent.addClass('extensions-viewlet'); + this.root = parent.getHTMLElement(); - this.root = append(parent.getHTMLElement(), $('.extensions-viewlet')); + const search = append(this.root, $('.search')); + this.searchBox = append(search, $('input.search-box')); + this.searchBox.placeholder = localize('searchExtensions', "Search Extensions"); + this.extensionsBox = append(this.root, $('.extensions')); + + const delegate = new Delegate(); + const renderer = this.instantiationService.createInstance(Renderer); + this.list = new PagedList(this.extensionsBox, delegate, [renderer]); + + this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); return TPromise.as(null); } setVisible(visible:boolean): TPromise { - return super.setVisible(visible); + return super.setVisible(visible).then(() => { + if (visible) { + this.searchBox.value = ''; + this.triggerSearch('', 0); + } + }); } focus(): void { super.focus(); } - layout(dimension: Dimension):void { - // noop + layout({ height }: Dimension):void { + this.list.layout(height - 50); + } + + private triggerSearch(text: string = '', delay = 500): void { + this.list.model = EmptyModel; + + const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); + + addClass(this.extensionsBox, 'loading'); + always(promise, () => removeClass(this.extensionsBox, 'loading')); + } + + private doSearch(text: string = ''): TPromise { + return this.galleryService.query({ text }) + .then(result => new PagedModel(mapPager(result, extension => ({ extension, state: ExtensionState.Installed })))) + .then(model => this.list.model = model); } dispose(): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css index a4a092d8349..d18539b39b4 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css @@ -2,3 +2,15 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + +.extensions-viewlet { + height: 100%; +} + +.extensions-viewlet > .search { + height: 50px; +} + +.extensions-viewlet > .extensions { + height: calc(100% - 50px); +} \ No newline at end of file From 2ffe9169db86df60b1a47d1d0b03867b0d9b5bdc Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 18 Apr 2016 16:24:53 +0200 Subject: [PATCH 026/126] extension viewlet css --- .../electron-browser/extensionsList.ts | 9 +- .../electron-browser/extensionsPart.ts | 6 +- .../electron-browser/extensionsViewlet.ts | 8 +- .../media/extensions-viewlet.css | 82 ++++++++++++++++++- 4 files changed, 90 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index d6f7da44ee2..21f0e418754 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -22,7 +22,6 @@ export interface ITemplateData { version: HTMLElement; author: HTMLElement; description: HTMLElement; - body: HTMLElement; } export enum ExtensionState { @@ -78,8 +77,7 @@ export class Renderer implements IPagedRenderer const version = append(subtitle, $('span.version')); const author = append(subtitle, $('span.author')); const description = append(details, $('.description')); - const body = append(element, $('.body')); - const result = { extension: null, container, element, icon, name, version, author, description, body }; + const result = { extension: null, container, element, icon, name, version, author, description }; this._templates.push(result); return result; @@ -88,12 +86,11 @@ export class Renderer implements IPagedRenderer renderPlaceholder(index: number, data: ITemplateData): void { addClass(data.element, 'loading'); data.extension = null; - data.icon.style.display = 'none'; + data.icon.src = ''; data.name.textContent = ''; data.version.textContent = ''; data.author.textContent = ''; data.description.textContent = ''; - data.body.textContent = ''; } renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { @@ -103,13 +100,11 @@ export class Renderer implements IPagedRenderer data.extension = extension; removeClass(data.element, 'loading'); - data.icon.style.display = 'block'; data.icon.src = version.iconUrl; data.name.textContent = extension.displayName; data.version.textContent = ` ${ extension.version }`; data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; data.description.textContent = extension.description; - data.body.textContent = ''; } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index 7b9221d7043..d544f4443f5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -197,15 +197,15 @@ export class ExtensionsPart extends BaseEditor { this.request(version.readmeUrl) .then(opts => assign(opts, { headers })) .then(opts => downloadText(opts)) - .then(marked.parse) - .then(html => data.body.innerHTML = html); + .then(marked.parse); + // .then(html => data.body.innerHTML = html); // set up disposable for later this.highlightDisposable = toDisposable(() => { listener.dispose(); container.appendChild(data.container); this.overlay.style.height = '0'; - data.body.innerHTML = ''; + // data.body.innerHTML = ''; }); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 546792f30f9..8ad240437e7 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -12,13 +12,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { Viewlet } from 'vs/workbench/browser/viewlet'; -import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { append, emmet as $ } from 'vs/base/browser/dom'; import { PagedModel, mapPager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionEntry, Delegate, Renderer, ExtensionState } from './extensionsList'; import { IGalleryService } from '../common/extensions'; +import { IProgressService } from 'vs/platform/progress/common/progress'; const EmptyModel = new PagedModel({ firstPage: [], @@ -41,6 +42,7 @@ export class ExtensionsViewlet extends Viewlet { constructor( @ITelemetryService telemetryService: ITelemetryService, @IGalleryService private galleryService: IGalleryService, + @IProgressService private progressService: IProgressService, @IInstantiationService private instantiationService: IInstantiationService ) { super(ExtensionsViewlet.ID, telemetryService); @@ -89,8 +91,8 @@ export class ExtensionsViewlet extends Viewlet { const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); - addClass(this.extensionsBox, 'loading'); - always(promise, () => removeClass(this.extensionsBox, 'loading')); + const progressRunner = this.progressService.show(true); + always(promise, () => progressRunner.done()); } private doSearch(text: string = ''): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css index d18539b39b4..79e3582c817 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css @@ -8,9 +8,87 @@ } .extensions-viewlet > .search { - height: 50px; + height: 38px; + box-sizing: border-box; + padding: 5px 9px 5px 16px; +} + +.extensions-viewlet > .search > .search-box { + width: 100%; + height: 100%; + box-sizing: border-box; + padding: 0 3px; } .extensions-viewlet > .extensions { - height: calc(100% - 50px); + height: calc(100% - 26px); +} + +.extensions-viewlet > .extensions .extension-container { + width: 100%; + height: 100%; +} + +.extensions-viewlet > .extensions .extension-container > .extension { + margin: 10px 20px 10px 17px; + width: calc(100% - 30px); + height: calc(100% - 20px); + overflow: hidden; + background-color: white; + box-shadow: 2px 2px 5px rgba(0,0,0,.1); +} + +.extensions-viewlet > .extensions .extension-container > .extension:hover { + box-shadow: 2px 2px 5px rgba(0,0,0,.25); +} + +.extensions-viewlet > .extensions .extension-container > .extension.loading { + background-image: url('loading.svg'); + background-position: center center; + background-repeat: no-repeat; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header { + display: flex; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .icon { + box-sizing: border-box; + width: 70px; + height: 70px; + padding: 8px; + flex-shrink: 0; +} + +.extensions-viewlet > .extensions .extension-container > .extension.loading > .header > .icon { + display: none; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .details { + flex: 1; + padding: 8px; + overflow: hidden; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .title > .name { + font-weight: bold; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .subtitle { + font-size: 90%; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .subtitle > .author { + font-style: italic; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > div { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + width: 100%; +} + +.extensions-viewlet > .extensions .extension-container > .extension > .body { + display: none; } \ No newline at end of file From 87c20d64da94d44ee034d696ec48f1d402455b1d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 18 Apr 2016 17:07:39 +0200 Subject: [PATCH 027/126] bit more theme fixing --- .../electron-browser/extensionsViewlet.ts | 2 +- .../media/extensions-viewlet.css | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 8ad240437e7..c6c858cbd20 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -83,7 +83,7 @@ export class ExtensionsViewlet extends Viewlet { } layout({ height }: Dimension):void { - this.list.layout(height - 50); + this.list.layout(height - 38); } private triggerSearch(text: string = '', delay = 500): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css index 79e3582c817..d1418b8ff8d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css @@ -10,7 +10,7 @@ .extensions-viewlet > .search { height: 38px; box-sizing: border-box; - padding: 5px 9px 5px 16px; + padding: 5px 19px 5px 16px; } .extensions-viewlet > .search > .search-box { @@ -21,7 +21,7 @@ } .extensions-viewlet > .extensions { - height: calc(100% - 26px); + height: calc(100% - 38px); } .extensions-viewlet > .extensions .extension-container { @@ -31,7 +31,6 @@ .extensions-viewlet > .extensions .extension-container > .extension { margin: 10px 20px 10px 17px; - width: calc(100% - 30px); height: calc(100% - 20px); overflow: hidden; background-color: white; @@ -91,4 +90,21 @@ .extensions-viewlet > .extensions .extension-container > .extension > .body { display: none; +} + +/* List overrides */ + +.extensions-viewlet .monaco-list-row:hover { + background-color: transparent; +} + +.extensions-viewlet .monaco-list-row.selected { + background-color: transparent; + color: inherit; +} + +.extensions-viewlet .monaco-list-row.selected .extension-container > .extension { + box-shadow: 2px 2px 5px rgba(0,0,0,.25); + background-color: #4FA7FF; + color: white; } \ No newline at end of file From f7dc8ba53c93fd45ae469ea988903ad735feb75e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 18 Apr 2016 21:53:01 +0200 Subject: [PATCH 028/126] update on extension inputs --- .../extensions/common/extensionsInput.ts | 33 +++++++++ .../extensions.contribution.ts | 12 +++- .../electron-browser/extensionsPart.ts | 72 +++++++++++++++++++ .../electron-browser/extensionsViewlet.ts | 21 ++++-- 4 files changed, 133 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 5d16fe3c841..8d43ec16f5c 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -8,6 +8,8 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; +import { IExtension } from 'vs/workbench/parts/extensions/common/extensions'; +import { extensionEquals } from 'vs/workbench/parts/extensions/common/extensionsUtil'; export class ExtensionsInput extends EditorInput { @@ -29,6 +31,37 @@ export class ExtensionsInput extends EditorInput { return other instanceof ExtensionsInput; } + resolve(refresh?: boolean): TPromise { + return TPromise.as(null); + } +} + +export class ExtensionsInput2 extends EditorInput { + + static get ID() { return 'workbench.extensions.input2'; } + get extension(): IExtension { return this._extension; } + + constructor(private _extension: IExtension) { + super(); + } + + getId(): string { + return ExtensionsInput.ID; + } + + getName(): string { + return this.extension.displayName; + } + + matches(other: any): boolean { + if (!(other instanceof ExtensionsInput2)) { + return false; + } + + const otherExtensionInput = other as ExtensionsInput2; + return extensionEquals(this.extension, otherExtensionInput.extension); + } + resolve(refresh?: boolean): TPromise { return TPromise.as(null); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 4fc87d2e02b..50a2273b9e5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -16,7 +16,7 @@ import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/elec import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory } from 'vs/workbench/browser/parts/editor/baseEditor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; +import { ExtensionsInput, ExtensionsInput2 } from 'vs/workbench/parts/extensions/common/extensionsInput'; import { ExtensionsPart } from 'vs/workbench/parts/extensions/electron-browser/extensionsPart'; import { GlobalExtensionsActionContributor } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; import { IActionBarRegistry, Scope as ActionBarScope, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; @@ -61,6 +61,16 @@ const editorDescriptor = new EditorDescriptor( Registry.as(EditorExtensions.Editors) .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); +const editorDescriptor2 = new EditorDescriptor( + 'workbench.editor.extensionsPart2', + localize('extension', "Extension"), + 'vs/workbench/parts/extensions/electron-browser/extensionsPart', + 'ExtensionsPart2' +); + +Registry.as(EditorExtensions.Editors) + .registerEditor(editorDescriptor2, [new SyncDescriptor(ExtensionsInput2)]); + Registry.as(ActionBarExtensions.Actionbar) .registerActionBarContributor(ActionBarScope.GLOBAL, GlobalExtensionsActionContributor); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts index d544f4443f5..755d6375ed7 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts @@ -21,12 +21,14 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IGalleryService } from '../common/extensions'; import { getExtensionId } from '../common/extensionsUtil'; +import { ExtensionsInput2 } from '../common/extensionsInput'; import { PagedModel, mapPager } from 'vs/base/common/paging'; import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { UserSettings } from 'vs/workbench/node/userSettings'; import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IExtensionEntry, ITemplateData, Delegate, Renderer, ExtensionState } from './extensionsList'; +import { EditorOptions } from 'vs/workbench/common/editor'; const EmptyModel = new PagedModel({ firstPage: [], @@ -232,3 +234,73 @@ export class ExtensionsPart extends BaseEditor { super.dispose(); } } + +export class ExtensionsPart2 extends BaseEditor { + + static ID: string = 'workbench.editor.extensionsPart2'; + + private root: HTMLElement; + + private _highlight: ITemplateData; + private highlightDisposable: IDisposable; + + private toDispose: IDisposable[]; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IGalleryService private galleryService: IGalleryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IInstantiationService private instantiationService: IInstantiationService + ) { + super(ExtensionsPart2.ID, telemetryService); + this._highlight = null; + this.highlightDisposable = empty; + this.toDispose = []; + } + + createEditor(parent: Builder): void { + const container = parent.getHTMLElement(); + this.root = append(container, $('.extension')); + } + + setInput(input: ExtensionsInput2, options: EditorOptions): TPromise { + this.root.innerHTML = ''; + + const [version] = input.extension.galleryInformation.versions; + const headers = version.downloadHeaders; + + return super.setInput(input, options) + .then(() => this.request(version.readmeUrl)) + .then(opts => assign(opts, { headers })) + .then(opts => downloadText(opts)) + .then(marked.parse) + .then(html => this.root.innerHTML = html); + } + + layout(): void { + return; + } + + // Helper for proxy business... shameful. + // This should be pushed down and not rely on the context service + private request(url: string): TPromise { + const settings = TPromise.join([ + UserSettings.getValue(this.contextService, 'http.proxy'), + UserSettings.getValue(this.contextService, 'http.proxyStrictSSL') + ]); + + return settings.then(settings => { + const proxyUrl: string = settings[0]; + const strictSSL: boolean = settings[1]; + const agent = getProxyAgent(url, { proxyUrl, strictSSL }); + + return { url, agent, strictSSL }; + }); + } + + dispose(): void { + this._highlight = null; + this.toDispose = dispose(this.toDispose); + super.dispose(); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index c6c858cbd20..e9cbb12a83c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -19,7 +19,9 @@ import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionEntry, Delegate, Renderer, ExtensionState } from './extensionsList'; import { IGalleryService } from '../common/extensions'; +import { ExtensionsInput2 } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; const EmptyModel = new PagedModel({ firstPage: [], @@ -32,7 +34,7 @@ export class ExtensionsViewlet extends Viewlet { static ID: string = 'workbench.viewlet.extensions'; - private toDispose: IDisposable[]; + private disposables: IDisposable[]; private searchDelayer: ThrottledDelayer; private root: HTMLElement; private searchBox: HTMLInputElement; @@ -43,11 +45,12 @@ export class ExtensionsViewlet extends Viewlet { @ITelemetryService telemetryService: ITelemetryService, @IGalleryService private galleryService: IGalleryService, @IProgressService private progressService: IProgressService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService ) { super(ExtensionsViewlet.ID, telemetryService); this.searchDelayer = new ThrottledDelayer(500); - this.toDispose = []; + this.disposables = []; } create(parent: Builder): TPromise { @@ -66,6 +69,16 @@ export class ExtensionsViewlet extends Viewlet { this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); + this.list.onSelectionChange(e => { + const [entry] = e.elements; + + if (!entry) { + return; + } + + return this.editorService.openEditor(new ExtensionsInput2(entry.extension)); + }, null, this.disposables); + return TPromise.as(null); } @@ -102,7 +115,7 @@ export class ExtensionsViewlet extends Viewlet { } dispose(): void { - this.toDispose = dispose(this.toDispose); + this.disposables = dispose(this.disposables); super.dispose(); } } From c536706231cc6f4bc985186566fe0eb9094d6a0a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 09:33:05 +0200 Subject: [PATCH 029/126] extensions icon --- .../parts/extensions/electron-browser/media/extensions.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 279e9ed00ba..35dc14fc6ce 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensions.css @@ -203,7 +203,7 @@ /* Global action */ -.manage-extensions-action { +.monaco-workbench > .activitybar .monaco-action-bar .action-label.extensions { background: url('extensions-status.svg'); background-size: 22px; background-repeat: no-repeat; From dd6e5ee5e7da30e65b0c25bc8caaa147b0cac99a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 09:37:45 +0200 Subject: [PATCH 030/126] remove extensions part --- .../extensions/common/extensionsInput.ts | 30 +- .../electron-browser/extensionEditor.ts | 95 ++++++ .../extensions.contribution.ts | 54 ++-- .../electron-browser/extensionsActions.ts | 34 +- .../electron-browser/extensionsPart.ts | 306 ------------------ .../electron-browser/extensionsViewlet.ts | 4 +- 6 files changed, 119 insertions(+), 404 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts delete mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 8d43ec16f5c..0d998c0d6af 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -5,7 +5,6 @@ 'use strict'; -import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; import { IExtension } from 'vs/workbench/parts/extensions/common/extensions'; @@ -13,31 +12,6 @@ import { extensionEquals } from 'vs/workbench/parts/extensions/common/extensions export class ExtensionsInput extends EditorInput { - static get ID() { return 'workbench.extensions.input'; } - - constructor() { - super(); - } - - getId(): string { - return ExtensionsInput.ID; - } - - getName(): string { - return localize('extension', 'Extensions'); - } - - matches(other: any): boolean { - return other instanceof ExtensionsInput; - } - - resolve(refresh?: boolean): TPromise { - return TPromise.as(null); - } -} - -export class ExtensionsInput2 extends EditorInput { - static get ID() { return 'workbench.extensions.input2'; } get extension(): IExtension { return this._extension; } @@ -54,11 +28,11 @@ export class ExtensionsInput2 extends EditorInput { } matches(other: any): boolean { - if (!(other instanceof ExtensionsInput2)) { + if (!(other instanceof ExtensionsInput)) { return false; } - const otherExtensionInput = other as ExtensionsInput2; + const otherExtensionInput = other as ExtensionsInput; return extensionEquals(this.extension, otherExtensionInput.extension); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts new file mode 100644 index 00000000000..307f56ba67a --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/extensions2'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { marked } from 'vs/base/common/marked/marked'; +import { assign } from 'vs/base/common/objects'; +import { IDisposable, empty, dispose } from 'vs/base/common/lifecycle'; +import { Builder } from 'vs/base/browser/builder'; +import { append, emmet as $ } from 'vs/base/browser/dom'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IGalleryService } from '../common/extensions'; +import { ExtensionsInput } from '../common/extensionsInput'; +import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; +import { UserSettings } from 'vs/workbench/node/userSettings'; +import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; +import { getProxyAgent } from 'vs/base/node/proxy'; +import { ITemplateData } from './extensionsList'; +import { EditorOptions } from 'vs/workbench/common/editor'; + +export class ExtensionEditor extends BaseEditor { + + static ID: string = 'workbench.editor.extension'; + + private root: HTMLElement; + + private _highlight: ITemplateData; + private highlightDisposable: IDisposable; + + private toDispose: IDisposable[]; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IGalleryService private galleryService: IGalleryService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @IInstantiationService private instantiationService: IInstantiationService + ) { + super(ExtensionEditor.ID, telemetryService); + this._highlight = null; + this.highlightDisposable = empty; + this.toDispose = []; + } + + createEditor(parent: Builder): void { + const container = parent.getHTMLElement(); + this.root = append(container, $('.extension')); + } + + setInput(input: ExtensionsInput, options: EditorOptions): TPromise { + this.root.innerHTML = ''; + + const [version] = input.extension.galleryInformation.versions; + const headers = version.downloadHeaders; + + return super.setInput(input, options) + .then(() => this.request(version.readmeUrl)) + .then(opts => assign(opts, { headers })) + .then(opts => downloadText(opts)) + .then(marked.parse) + .then(html => this.root.innerHTML = html); + } + + layout(): void { + return; + } + + // Helper for proxy business... shameful. + // This should be pushed down and not rely on the context service + private request(url: string): TPromise { + const settings = TPromise.join([ + UserSettings.getValue(this.contextService, 'http.proxy'), + UserSettings.getValue(this.contextService, 'http.proxyStrictSSL') + ]); + + return settings.then(settings => { + const proxyUrl: string = settings[0]; + const strictSSL: boolean = settings[1]; + const agent = getProxyAgent(url, { proxyUrl, strictSSL }); + + return { url, agent, strictSSL }; + }); + } + + dispose(): void { + this._highlight = null; + this.toDispose = dispose(this.toDispose); + super.dispose(); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 50a2273b9e5..290406cbc99 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -14,28 +14,25 @@ import { GalleryService } from 'vs/workbench/parts/extensions/common/vsoGalleryS import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; -import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/parts/editor/baseEditor'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { ExtensionsInput, ExtensionsInput2 } from 'vs/workbench/parts/extensions/common/extensionsInput'; -import { ExtensionsPart } from 'vs/workbench/parts/extensions/electron-browser/extensionsPart'; -import { GlobalExtensionsActionContributor } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; -import { IActionBarRegistry, Scope as ActionBarScope, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; -import { EditorInput } from 'vs/workbench/common/editor'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; +// import { EditorInput } from 'vs/workbench/common/editor'; +// import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -class ExtensionsInputFactory implements IEditorInputFactory { +// class ExtensionsInputFactory implements IEditorInputFactory { - constructor() {} +// constructor() {} - public serialize(editorInput: EditorInput): string { - return ''; - } +// public serialize(editorInput: EditorInput): string { +// return ''; +// } - public deserialize(instantiationService: IInstantiationService, resourceRaw: string): EditorInput { - return instantiationService.createInstance(ExtensionsInput); - } -} +// public deserialize(instantiationService: IInstantiationService, resourceRaw: string): EditorInput { +// return instantiationService.createInstance(ExtensionsInput); +// } +// } registerSingleton(IGalleryService, GalleryService); @@ -48,32 +45,19 @@ Registry.as(StatusbarExtensions.Statusbar) Registry.as(OutputExtensions.OutputChannels) .registerChannel(ExtensionsChannelId, ExtensionsLabel); -Registry.as(EditorExtensions.Editors) - .registerEditorInputFactory(ExtensionsInput.ID, ExtensionsInputFactory); +// Registry.as(EditorExtensions.Editors) +// .registerEditorInputFactory(ExtensionsInput.ID, ExtensionsInputFactory); const editorDescriptor = new EditorDescriptor( - ExtensionsPart.ID, - localize('extensions', "Extensions"), - 'vs/workbench/parts/extensions/electron-browser/extensionsPart', - 'ExtensionsPart' + 'workbench.editor.extension', + localize('extension', "Extension"), + 'vs/workbench/parts/extensions/electron-browser/extensionEditor', + 'ExtensionEditor' ); Registry.as(EditorExtensions.Editors) .registerEditor(editorDescriptor, [new SyncDescriptor(ExtensionsInput)]); -const editorDescriptor2 = new EditorDescriptor( - 'workbench.editor.extensionsPart2', - localize('extension', "Extension"), - 'vs/workbench/parts/extensions/electron-browser/extensionsPart', - 'ExtensionsPart2' -); - -Registry.as(EditorExtensions.Editors) - .registerEditor(editorDescriptor2, [new SyncDescriptor(ExtensionsInput2)]); - -Registry.as(ActionBarExtensions.Actionbar) - .registerActionBarContributor(ActionBarScope.GLOBAL, GlobalExtensionsActionContributor); - const viewletDescriptor = new ViewletDescriptor( 'vs/workbench/parts/extensions/electron-browser/extensionsViewlet', 'ExtensionsViewlet', diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 7994608a218..af50e5a6ad7 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -5,7 +5,7 @@ import nls = require('vs/nls'); import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IAction, Action } from 'vs/base/common/actions'; +import { Action } from 'vs/base/common/actions'; import { assign } from 'vs/base/common/objects'; import Severity from 'vs/base/common/severity'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -15,10 +15,6 @@ import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { IExtensionsService, IExtension } from 'vs/workbench/parts/extensions/common/extensions'; import { extensionEquals, getTelemetryData } from 'vs/workbench/parts/extensions/common/extensionsUtil'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; -import { ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; -import { CONTEXT as ToolbarContext } from 'vs/base/browser/ui/toolbar/toolbar'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput'; const CloseAction = new Action('action.close', nls.localize('close', "Close")); @@ -212,31 +208,3 @@ export class UninstallAction extends Action { this.telemetryService.publicLog('extensionGallery:uninstall', data); } } - -class ManageExtensionsAction extends Action { - - constructor(@IWorkbenchEditorService private editorService: IWorkbenchEditorService) { - super('extensions.manage', nls.localize('openExtensions', "Manage Extensions"), 'manage-extensions-action'); - } - - run(): TPromise { - return this.editorService.openEditor(new ExtensionsInput()); - } -} - -export class GlobalExtensionsActionContributor extends ActionBarContributor { - - constructor(@IInstantiationService protected instantiationService: IInstantiationService) { - super(); - } - - public hasActions(context:any):boolean { - return context === ToolbarContext; - } - - public getActions(context:any): IAction[] { - return [ - this.instantiationService.createInstance(ManageExtensionsAction) - ]; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts deleted file mode 100644 index 755d6375ed7..00000000000 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsPart.ts +++ /dev/null @@ -1,306 +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!./media/extensions2'; -import { localize } from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { ThrottledDelayer, always } from 'vs/base/common/async'; -import { marked } from 'vs/base/common/marked/marked'; -import { assign } from 'vs/base/common/objects'; -import { IDisposable, toDisposable, empty, dispose } from 'vs/base/common/lifecycle'; -import { Builder } from 'vs/base/browser/builder'; -import { append, emmet as $, addClass, removeClass, getDomNodePosition, addDisposableListener } from 'vs/base/browser/dom'; -import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; -import { Position } from 'vs/platform/editor/common/editor'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { PagedList } from 'vs/base/browser/ui/list/listPaging'; -import { IGalleryService } from '../common/extensions'; -import { getExtensionId } from '../common/extensionsUtil'; -import { ExtensionsInput2 } from '../common/extensionsInput'; -import { PagedModel, mapPager } from 'vs/base/common/paging'; -import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; -import { UserSettings } from 'vs/workbench/node/userSettings'; -import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; -import { getProxyAgent } from 'vs/base/node/proxy'; -import { IExtensionEntry, ITemplateData, Delegate, Renderer, ExtensionState } from './extensionsList'; -import { EditorOptions } from 'vs/workbench/common/editor'; - -const EmptyModel = new PagedModel({ - firstPage: [], - total: 0, - pageSize: 0, - getPage: null -}); - -export class ExtensionsPart extends BaseEditor { - - static ID: string = 'workbench.editor.extensionsPart'; - - private list: PagedList; - private searchDelayer: ThrottledDelayer; - private root: HTMLElement; - private searchBox: HTMLInputElement; - private extensionsBox: HTMLElement; - private overlay: HTMLElement; - - private _highlight: ITemplateData; - private highlightDisposable: IDisposable; - - private toDispose: IDisposable[]; - - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IGalleryService private galleryService: IGalleryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IInstantiationService private instantiationService: IInstantiationService - ) { - super(ExtensionsPart.ID, telemetryService); - this.searchDelayer = new ThrottledDelayer(500); - this._highlight = null; - this.highlightDisposable = empty; - this.toDispose = []; - } - - createEditor(parent: Builder): void { - const container = parent.getHTMLElement(); - this.root = append(container, $('.extension-manager')); - - this.toDispose.push(addDisposableListener(this.root, 'click', e => { - if (e.target === this.root && this.highlight) { - this.highlight = null; - } - })); - - const search = append(this.root, $('.search')); - this.searchBox = append(search, $('input.search-box')); - this.searchBox.placeholder = localize('searchExtensions', "Search Extensions"); - this.extensionsBox = append(this.root, $('.extensions')); - - const delegate = new Delegate(); - const renderer = this.instantiationService.createInstance(Renderer); - this.list = new PagedList(this.extensionsBox, delegate, [renderer]); - - this.overlay = append(this.extensionsBox, $('.overlay')); - - this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); - - this.list.onSelectionChange(({ elements }) => { - if (this.highlightDisposable) { - removeClass(this.root, 'animated'); - this.highlightDisposable.dispose(); - this.highlightDisposable = empty; - } - - const [selected] = elements; - - if (!selected) { - return; - } - - const id = getExtensionId(selected.extension); - const [data] = renderer.templates.filter(t => t.extension && getExtensionId(t.extension) === id); - - if (!data) { - return; - } - - this.highlight = data; - }); - } - - setVisible(visible: boolean, position?: Position): TPromise { - return super.setVisible(visible, position).then(() => { - if (visible) { - this.highlight = null; - this.searchBox.value = ''; - this.triggerSearch('', 0); - } - }); - } - - layout({ height }): void { - height -= 72; - this.extensionsBox.style.height = `${ height }px`; - this.list.layout(height); - - if (this.highlight) { - this.overlay.style.height = this.extensionsBox.style.height; - } - } - - focus(): void { - this.searchBox.focus(); - } - - private triggerSearch(text: string = '', delay = 500): void { - this.highlight = null; - this.list.model = EmptyModel; - - const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); - - addClass(this.extensionsBox, 'loading'); - always(promise, () => removeClass(this.extensionsBox, 'loading')); - } - - private doSearch(text: string = ''): TPromise { - return this.galleryService.query({ text }) - .then(result => new PagedModel(mapPager(result, extension => ({ extension, state: ExtensionState.Installed })))) - .then(model => this.list.model = model); - } - - private get highlight(): ITemplateData { - return this._highlight; - } - - private set highlight(data: ITemplateData) { - this._highlight = data; - - if (!data) { - removeClass(this.root, 'highlighted'); - removeClass(this.root, 'animated'); - removeClass(this.root, 'highlight-in'); - this.highlightDisposable.dispose(); - this.highlightDisposable = empty; - return; - } - - const position = getDomNodePosition(data.container); - const rootPosition = getDomNodePosition(this.extensionsBox); - - this.overlay.style.top = `${ position.top - rootPosition.top - this.list.scrollTop }px`; - this.overlay.style.height = `${ position.height }px`; - let _ = this.overlay.offsetHeight; _++; // trigger reflow - - addClass(this.root, 'animated highlight-in'); - this.overlay.style.top = '0'; - this.overlay.style.height = this.extensionsBox.style.height; - - // swap parents - const container = data.container.parentElement; - this.overlay.appendChild(data.container); - - // transition end event - const listener = addDisposableListener(this.overlay, 'transitionend', e => { - listener.dispose(); - removeClass(this.root, 'animated'); - removeClass(this.root, 'highlight-in'); - addClass(this.root, 'highlighted'); - }); - - const [version] = data.extension.galleryInformation.versions; - const headers = version.downloadHeaders; - - // TODO - this.request(version.readmeUrl) - .then(opts => assign(opts, { headers })) - .then(opts => downloadText(opts)) - .then(marked.parse); - // .then(html => data.body.innerHTML = html); - - // set up disposable for later - this.highlightDisposable = toDisposable(() => { - listener.dispose(); - container.appendChild(data.container); - this.overlay.style.height = '0'; - // data.body.innerHTML = ''; - }); - } - - // Helper for proxy business... shameful. - // This should be pushed down and not rely on the context service - private request(url: string): TPromise { - const settings = TPromise.join([ - UserSettings.getValue(this.contextService, 'http.proxy'), - UserSettings.getValue(this.contextService, 'http.proxyStrictSSL') - ]); - - return settings.then(settings => { - const proxyUrl: string = settings[0]; - const strictSSL: boolean = settings[1]; - const agent = getProxyAgent(url, { proxyUrl, strictSSL }); - - return { url, agent, strictSSL }; - }); - } - - dispose(): void { - this._highlight = null; - this.toDispose = dispose(this.toDispose); - super.dispose(); - } -} - -export class ExtensionsPart2 extends BaseEditor { - - static ID: string = 'workbench.editor.extensionsPart2'; - - private root: HTMLElement; - - private _highlight: ITemplateData; - private highlightDisposable: IDisposable; - - private toDispose: IDisposable[]; - - constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IGalleryService private galleryService: IGalleryService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IInstantiationService private instantiationService: IInstantiationService - ) { - super(ExtensionsPart2.ID, telemetryService); - this._highlight = null; - this.highlightDisposable = empty; - this.toDispose = []; - } - - createEditor(parent: Builder): void { - const container = parent.getHTMLElement(); - this.root = append(container, $('.extension')); - } - - setInput(input: ExtensionsInput2, options: EditorOptions): TPromise { - this.root.innerHTML = ''; - - const [version] = input.extension.galleryInformation.versions; - const headers = version.downloadHeaders; - - return super.setInput(input, options) - .then(() => this.request(version.readmeUrl)) - .then(opts => assign(opts, { headers })) - .then(opts => downloadText(opts)) - .then(marked.parse) - .then(html => this.root.innerHTML = html); - } - - layout(): void { - return; - } - - // Helper for proxy business... shameful. - // This should be pushed down and not rely on the context service - private request(url: string): TPromise { - const settings = TPromise.join([ - UserSettings.getValue(this.contextService, 'http.proxy'), - UserSettings.getValue(this.contextService, 'http.proxyStrictSSL') - ]); - - return settings.then(settings => { - const proxyUrl: string = settings[0]; - const strictSSL: boolean = settings[1]; - const agent = getProxyAgent(url, { proxyUrl, strictSSL }); - - return { url, agent, strictSSL }; - }); - } - - dispose(): void { - this._highlight = null; - this.toDispose = dispose(this.toDispose); - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index e9cbb12a83c..5ee942077e5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -19,7 +19,7 @@ import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionEntry, Delegate, Renderer, ExtensionState } from './extensionsList'; import { IGalleryService } from '../common/extensions'; -import { ExtensionsInput2 } from '../common/extensionsInput'; +import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -76,7 +76,7 @@ export class ExtensionsViewlet extends Viewlet { return; } - return this.editorService.openEditor(new ExtensionsInput2(entry.extension)); + return this.editorService.openEditor(new ExtensionsInput(entry.extension)); }, null, this.disposables); return TPromise.as(null); From a0850eebf01d8dfaffec4eca917d2ba189d67f1e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 09:50:00 +0200 Subject: [PATCH 031/126] create global viewlet toolbar --- .../parts/activitybar/activitybarPart.ts | 64 ++++++++++++------- src/vs/workbench/browser/viewlet.ts | 13 +++- .../extensions.contribution.ts | 3 +- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index ec8640eda1e..4f8173a427b 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -35,6 +35,7 @@ import events = require('vs/base/common/events'); export class ActivitybarPart extends Part implements IActivityService { public serviceId = IActivityService; private viewletSwitcherBar: ActionBar; + private globalViewletSwitcherBar: ActionBar; private globalToolBar: ToolBar; private activityActionItems: { [actionId: string]: IActionItem; }; private viewletIdToActions: { [viewletId: string]: ActivityAction; }; @@ -126,34 +127,53 @@ export class ActivitybarPart extends Part implements IActivityService { }); this.viewletSwitcherBar.getContainer().addClass('position-top'); + // Global viewlet switcher is right below + this.globalViewletSwitcherBar = new ActionBar(div, { + actionItemProvider: (action: Action) => this.activityActionItems[action.id], + orientation: ActionsOrientation.VERTICAL, + ariaLabel: nls.localize('globalActivityBarAriaLabel', "Active Global View Switcher") + }); + this.globalViewletSwitcherBar.getContainer().addClass('position-bottom'); + // Build Viewlet Actions in correct order - let activeViewlet = this.viewletService.getActiveViewlet(); - let registry = (Registry.as(ViewletExtensions.Viewlets)); - let viewletActions: Action[] = registry.getViewlets() - .sort((v1: ViewletDescriptor, v2: ViewletDescriptor) => v1.order - v2.order) - .map((viewlet: ViewletDescriptor) => { - let action = this.instantiationService.createInstance(ViewletActivityAction, viewlet.id + '.activity-bar-action', viewlet); + const activeViewlet = this.viewletService.getActiveViewlet(); + const registry = (Registry.as(ViewletExtensions.Viewlets)); + const allViewletActions = registry.getViewlets(); + const actionOptions = { label: true, icon: true }; - let keybinding: string = null; - let keys = this.keybindingService.lookupKeybindings(viewlet.id).map(k => this.keybindingService.getLabelFor(k)); - if (keys && keys.length) { - keybinding = keys[0]; - } + const toAction = (viewlet: ViewletDescriptor) => { + let action = this.instantiationService.createInstance(ViewletActivityAction, viewlet.id + '.activity-bar-action', viewlet); - this.activityActionItems[action.id] = new ActivityActionItem(action, viewlet.name, keybinding); - this.viewletIdToActions[viewlet.id] = action; - - // Mark active viewlet action as active - if (activeViewlet && activeViewlet.getId() === viewlet.id) { - action.activate(); - } - - return action; + let keybinding: string = null; + let keys = this.keybindingService.lookupKeybindings(viewlet.id).map(k => this.keybindingService.getLabelFor(k)); + if (keys && keys.length) { + keybinding = keys[0]; } - ); + + this.activityActionItems[action.id] = new ActivityActionItem(action, viewlet.name, keybinding); + this.viewletIdToActions[viewlet.id] = action; + + // Mark active viewlet action as active + if (activeViewlet && activeViewlet.getId() === viewlet.id) { + action.activate(); + } + + return action; + }; // Add to viewlet switcher - this.viewletSwitcherBar.push(viewletActions, { label: true, icon: true }); + this.viewletSwitcherBar.push(allViewletActions + .filter(v => !v.isGlobal) + .sort((v1, v2) => v1.order - v2.order) + .map(toAction) + , actionOptions); + + // Add to viewlet switcher + this.globalViewletSwitcherBar.push(allViewletActions + .filter(v => v.isGlobal) + .sort((v1, v2) => v1.order - v2.order) + .map(toAction), + actionOptions); } private createGlobalToolBarArea(div: Builder): void { diff --git a/src/vs/workbench/browser/viewlet.ts b/src/vs/workbench/browser/viewlet.ts index 1b7ff3b84c9..fbd4801854f 100644 --- a/src/vs/workbench/browser/viewlet.ts +++ b/src/vs/workbench/browser/viewlet.ts @@ -158,7 +158,14 @@ export abstract class ViewerViewlet extends Viewlet { /** * A viewlet descriptor is a leightweight descriptor of a viewlet in the monaco workbench. */ -export class ViewletDescriptor extends CompositeDescriptor { } +export class ViewletDescriptor extends CompositeDescriptor { + public isGlobal: boolean; + + constructor(moduleId: string, ctorName: string, id: string, name: string, cssClass?: string, order?: number, isGlobal?: boolean) { + super(moduleId, ctorName, id, name, cssClass, order); + this.isGlobal = isGlobal || false; + } +} export const Extensions = { Viewlets: 'workbench.contributions.viewlets' @@ -178,14 +185,14 @@ export class ViewletRegistry extends CompositeRegistry { * Returns the viewlet descriptor for the given id or null if none. */ public getViewlet(id: string): ViewletDescriptor { - return this.getComposite(id); + return this.getComposite(id) as ViewletDescriptor; } /** * Returns an array of registered viewlets known to the platform. */ public getViewlets(): ViewletDescriptor[] { - return this.getComposits(); + return this.getComposits() as ViewletDescriptor[]; } /** diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 290406cbc99..8d19bdd30ca 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -64,7 +64,8 @@ const viewletDescriptor = new ViewletDescriptor( 'workbench.viewlet.extensions', localize('extensions', "Extensions"), 'extensions', - 100 + 100, + true ); Registry.as(ViewletExtensions.Viewlets) From 683ed4ed93f6a653ab14593669d9bf67288160bf Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 09:50:07 +0200 Subject: [PATCH 032/126] focus search box on focus --- .../parts/extensions/electron-browser/extensionsViewlet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 5ee942077e5..e64284e731e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -92,7 +92,7 @@ export class ExtensionsViewlet extends Viewlet { } focus(): void { - super.focus(); + this.searchBox.focus(); } layout({ height }: Dimension):void { From 97bf47bf417b58ef4ae8b3ab8c8f86ab2249c5b8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 09:52:13 +0200 Subject: [PATCH 033/126] remove leftovers --- .../electron-browser/extensionEditor.ts | 1 - .../electron-browser/extensionsList.ts | 1 - .../electron-browser/media/extensions2.css | 161 ------------------ 3 files changed, 163 deletions(-) delete mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 307f56ba67a..80836f837ac 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -5,7 +5,6 @@ 'use strict'; -import 'vs/css!./media/extensions2'; import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; import { assign } from 'vs/base/common/objects'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 21f0e418754..ecf66c9a41e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -5,7 +5,6 @@ 'use strict'; -import 'vs/css!./media/extensions2'; import { localize } from 'vs/nls'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css deleted file mode 100644 index eb5b24278d1..00000000000 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensions2.css +++ /dev/null @@ -1,161 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Extension Manager */ - -.extension-manager { - position: relative; - background: #f1f1f1; - width: 100%; - height: 100%; -} - -.extension-manager > .search, -.extension-manager > .extensions { - width: 100%; - max-width: 800px; - margin: 0 auto; -} - -.extension-manager > .search { - box-sizing: border-box; - padding: 10px; - height: 72px; -} - -.extension-manager > .search > .search-box { - margin: 10px 0; - width: calc(100% - 28px); /* TODO: HACK */ - padding: 10px 8px; - font-size: 16px; - border: 1px solid gainsboro; -} - -.extension-manager > .extensions { - position: relative; - overflow: hidden; -} - -.extension-manager .extensions.loading { - background-image: url('loading.svg'); - background-position: top center; - background-repeat: no-repeat; -} - -.extension-manager > .extensions > .overlay { - box-sizing: border-box; - position: absolute; - width: 100%; - left: 0; - padding: 0 20px 0 10px; -} - -.extension-manager.animated > .extensions > .overlay { - transition-property: top, height, padding; - transition-duration: 0.2s; - transition-timing-function: ease-out; -} - -.extension-manager > .extensions > .monaco-list { - transition-property: opacity; - transition-duration: 0.2s; - transition-timing-function: ease-out; -} - -.extension-manager.highlight-in > .extensions > .monaco-list { - opacity: 0; -} - -.extension-manager.highlighted > .extensions > .monaco-list { - display: none; -} - -.extension-manager .monaco-list-row.selected { - background-color: inherit; - color: inherit; -} - -.extension-manager .monaco-list-row:hover { - background-color: inherit; -} - -.extension-manager .extension-container { - width: 100%; - height: 100%; -} - -.extension-manager .extension-container > .extension { - margin: 10px 20px 10px 10px; - width: calc(100% - 30px); - height: calc(100% - 20px); - overflow: hidden; - display: flex; - flex-direction: column; -} - -.extension-manager .overlay .extension-container > .extension { - margin: 0; - width: 100%; - height: 100%; -} - -.extension-manager > .extensions > .overlay > .highlighted-extension, -.extension-manager .extension-container > .extension { - background-color: white; -} - -.extension-manager .monaco-list .extension-container > .extension { - box-shadow: 2px 2px 5px rgba(0,0,0,.1); -} - -.extension-manager .monaco-list .extension-container > .extension:hover { - box-shadow: 2px 2px 5px rgba(0,0,0,.25); -} - -.extension-manager .extension-container > .extension.loading { - background-image: url('loading.svg'); - background-position: center center; - background-repeat: no-repeat; -} - -.extension-manager .extension-container > .extension > .header { - display: flex; -} - -.extension-manager .extension-container > .extension > .header > .icon { - box-sizing: border-box; - width: 70px; - height: 70px; - padding: 8px; -} - -.extension-manager .extension-container > .extension > .header > .details { - flex: 1; - padding: 8px; -} - -.extension-manager .extension-container > .extension > .header > .details > .title > .name { - font-weight: bold; -} - -.extension-manager .extension-container > .extension > .header > .details > .subtitle { - font-size: 90%; -} - -.extension-manager .extension-container > .extension > .header > .details > .subtitle > .author { - font-style: italic; -} - -.extension-manager .extension-container > .extension > .header > .details > div { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.extension-manager .extension-container > .extension > .body { - flex: 1; - overflow-y: scroll; - padding: 10px; -} \ No newline at end of file From 901a20050944f5d1ad7c189c6d0ec73a9387d537 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 10:07:48 +0200 Subject: [PATCH 034/126] pimp up extension editor --- .../electron-browser/extensionEditor.ts | 37 ++++++++++++++----- .../electron-browser/extensionsViewlet.ts | 2 +- .../media/extensionEditor.css | 35 ++++++++++++++++++ ...ions-viewlet.css => extensionsViewlet.css} | 0 4 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css rename src/vs/workbench/parts/extensions/electron-browser/media/{extensions-viewlet.css => extensionsViewlet.css} (100%) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 80836f837ac..737b4b51d06 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -5,12 +5,13 @@ 'use strict'; +import 'vs/css!./media/extensionEditor'; import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; import { assign } from 'vs/base/common/objects'; -import { IDisposable, empty, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; -import { append, emmet as $ } from 'vs/base/browser/dom'; +import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -27,12 +28,13 @@ export class ExtensionEditor extends BaseEditor { static ID: string = 'workbench.editor.extension'; - private root: HTMLElement; + private body: HTMLElement; private _highlight: ITemplateData; private highlightDisposable: IDisposable; - private toDispose: IDisposable[]; + private transientDisposables: IDisposable[]; + private disposables: IDisposable[]; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -43,26 +45,40 @@ export class ExtensionEditor extends BaseEditor { super(ExtensionEditor.ID, telemetryService); this._highlight = null; this.highlightDisposable = empty; - this.toDispose = []; + this.disposables = []; } createEditor(parent: Builder): void { const container = parent.getHTMLElement(); - this.root = append(container, $('.extension')); + + const root = append(container, $('.extension-editor')); + const header = append(root, $('.header')); + header.innerText = 'here goes description, author name, links, ratings, install buttons, etc'; + this.body = append(root, $('.body')); } setInput(input: ExtensionsInput, options: EditorOptions): TPromise { - this.root.innerHTML = ''; + this.transientDisposables = dispose(this.transientDisposables); + + addClass(this.body, 'loading'); + this.body.innerHTML = ''; const [version] = input.extension.galleryInformation.versions; const headers = version.downloadHeaders; - return super.setInput(input, options) + const promise = super.setInput(input, options) .then(() => this.request(version.readmeUrl)) .then(opts => assign(opts, { headers })) .then(opts => downloadText(opts)) .then(marked.parse) - .then(html => this.root.innerHTML = html); + .then(html => { + removeClass(this.body, 'loading'); + this.body.innerHTML = html; + }); + + this.transientDisposables.push(toDisposable(() => promise.cancel())); + + return TPromise.as(null); } layout(): void { @@ -88,7 +104,8 @@ export class ExtensionEditor extends BaseEditor { dispose(): void { this._highlight = null; - this.toDispose = dispose(this.toDispose); + this.transientDisposables = dispose(this.transientDisposables); + this.disposables = dispose(this.disposables); super.dispose(); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index e64284e731e..cc454c86376 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -5,7 +5,7 @@ 'use strict'; -import 'vs/css!./media/extensions-viewlet'; +import 'vs/css!./media/extensionsViewlet'; import { localize } from 'vs/nls'; import { ThrottledDelayer, always } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css new file mode 100644 index 00000000000..eb573959f18 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.extension-editor { + height: 100%; + overflow-y: scroll; + display: flex; + flex-direction: column; + /*padding: 20px;*/ +} + +.extension-editor > .header { + height: 40px; + background: #E2E2E2; /* TODO */ + padding: 20px; +} + +.extension-editor > .body { + flex: 1; + overflow-y: scroll; + overflow-x: hidden; + padding: 20px; +} + +.extension-editor > .body img { + max-width: 100%; +} + +.extension-editor > .body.loading { + background-image: url('loading.svg'); + background-position: center center; + background-repeat: no-repeat; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css similarity index 100% rename from src/vs/workbench/parts/extensions/electron-browser/media/extensions-viewlet.css rename to src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css From eb8ef77c355295042a8e2245f26617dec27eaaee Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 19 Apr 2016 10:14:06 +0200 Subject: [PATCH 035/126] dark theme --- .../media/extensionEditor.css | 2 +- .../media/extensionsViewlet.css | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index eb573959f18..b7d968f605f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -13,7 +13,7 @@ .extension-editor > .header { height: 40px; - background: #E2E2E2; /* TODO */ + background: rgba(128, 128, 128, 0.15); /* TODO */ padding: 20px; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index d1418b8ff8d..60dec9cb341 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -103,8 +103,27 @@ color: inherit; } +/* Themeing */ + +.vs-dark .extensions-viewlet > .extensions .extension-container > .extension { + background-color: #333333; + box-shadow: 2px 2px 5px rgba(0,0,0,.3); +} + +.vs-dark .extensions-viewlet > .extensions .extension-container > .extension:hover { + box-shadow: 2px 2px 5px rgba(0,0,0,.7); +} + +/* Selection */ + .extensions-viewlet .monaco-list-row.selected .extension-container > .extension { box-shadow: 2px 2px 5px rgba(0,0,0,.25); background-color: #4FA7FF; color: white; +} + +.vs-dark .extensions-viewlet .monaco-list-row.selected .extension-container > .extension { + box-shadow: 2px 2px 5px rgba(0,0,0,.7); + background-color: #0E639C; + color: white; } \ No newline at end of file From 742dcb3a83dbffb4543d31a1c902ab43348176f2 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 15 Jun 2016 09:54:51 +0200 Subject: [PATCH 036/126] docs --- src/vs/base/common/paging.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/vs/base/common/paging.ts b/src/vs/base/common/paging.ts index ee6d1b28ddc..5706b6c3c85 100644 --- a/src/vs/base/common/paging.ts +++ b/src/vs/base/common/paging.ts @@ -8,6 +8,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ArraySet } from 'vs/base/common/set'; +/** + * A Pager is a stateless abstraction over a paged collection. + */ export interface IPager { firstPage: T[]; total: number; @@ -22,7 +25,17 @@ interface IPage { elements: T[]; } -export class PagedModel { +/** + * A PagedModel is a stateful model over an abstracted paged collection. + */ +export interface IPagedModel { + length: number; + isResolved(index: number): boolean; + get(index: number): T; + resolve(index: number): TPromise; +} + +export class PagedModel implements IPagedModel { private pages: IPage[] = []; @@ -92,6 +105,10 @@ export class PagedModel { } } +/** + * Similar to array.map, `mapPager` lets you map the elements of an + * abstract paged collection to another type. + */ export function mapPager(pager: IPager, fn: (t: T) => R): IPager { return { firstPage: pager.firstPage.map(fn), From e3c4f05e634a672adcfbbd06317d0e0f9ae6e26c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 15 Jun 2016 10:39:22 +0200 Subject: [PATCH 037/126] simplify theme --- .../electron-browser/extensionsList.ts | 39 ++----- .../media/extensionsViewlet.css | 105 ++++++------------ 2 files changed, 43 insertions(+), 101 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 5734740264e..5337073f50a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -5,7 +5,6 @@ 'use strict'; -import { localize } from 'vs/nls'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; @@ -14,7 +13,6 @@ import { IExtension } from 'vs/platform/extensionManagement/common/extensionMana export interface ITemplateData { extension: IExtension; - container: HTMLElement; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -34,20 +32,8 @@ export interface IExtensionEntry { state: ExtensionState; } -// function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { -// const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; -// const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; -// const diff = otherInstallCount - oneInstallCount; - -// if (diff !== 0) { -// return diff; -// } - -// return one.extension.displayName.localeCompare(other.extension.displayName); -// } - export class Delegate implements IDelegate { - getHeight() { return 90; } + getHeight() { return 62; } getTemplateId() { return 'extension'; } } @@ -65,18 +51,15 @@ export class Renderer implements IPagedRenderer get templateId() { return 'extension'; } renderTemplate(root: HTMLElement): ITemplateData { - const container = append(root, $('.extension-container')); - const element = append(container, $('.extension')); - const header = append(element, $('.header')); - const icon = append(header, $('img.icon')); - const details = append(header, $('.details')); - const title = append(details, $('.title')); - const subtitle = append(details, $('.subtitle')); - const name = append(title, $('span.name')); - const version = append(subtitle, $('span.version')); - const author = append(subtitle, $('span.author')); - const description = append(details, $('.description')); - const result = { extension: null, container, element, icon, name, version, author, description }; + const element = append(root, $('.extension')); + const icon = append(element, $('img.icon')); + const details = append(element, $('.details')); + const header = append(details, $('.header')); + const name = append(header, $('span.name.ellipsis')); + const version = append(header, $('span.version.ellipsis')); + const author = append(header, $('span.author.ellipsis')); + const description = append(details, $('.description.ellipsis')); + const result = { extension: null, element, icon, name, version, author, description }; this._templates.push(result); return result; @@ -102,7 +85,7 @@ export class Renderer implements IPagedRenderer data.icon.src = version.iconUrl; data.name.textContent = extension.displayName; data.version.textContent = ` ${ extension.version }`; - data.author.textContent = ` ${ localize('author', "by {0}", publisher)}`; + data.author.textContent = ` ${ publisher }`; data.description.textContent = extension.description; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index 60dec9cb341..d96250e257b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -24,106 +24,65 @@ height: calc(100% - 38px); } -.extensions-viewlet > .extensions .extension-container { +.extensions-viewlet > .extensions .extension { + box-sizing: border-box; width: 100%; height: 100%; -} - -.extensions-viewlet > .extensions .extension-container > .extension { - margin: 10px 20px 10px 17px; - height: calc(100% - 20px); + padding: 0 19px 0 16px; overflow: hidden; - background-color: white; - box-shadow: 2px 2px 5px rgba(0,0,0,.1); + display: flex; } -.extensions-viewlet > .extensions .extension-container > .extension:hover { - box-shadow: 2px 2px 5px rgba(0,0,0,.25); -} - -.extensions-viewlet > .extensions .extension-container > .extension.loading { +.extensions-viewlet > .extensions .extension.loading { background-image: url('loading.svg'); background-position: center center; background-repeat: no-repeat; } -.extensions-viewlet > .extensions .extension-container > .extension > .header { - display: flex; -} - -.extensions-viewlet > .extensions .extension-container > .extension > .header > .icon { - box-sizing: border-box; - width: 70px; - height: 70px; - padding: 8px; +.extensions-viewlet > .extensions .extension > .icon { + width: 42px; + height: 42px; + padding: 10px 14px 10px 0; flex-shrink: 0; } -.extensions-viewlet > .extensions .extension-container > .extension.loading > .header > .icon { +.extensions-viewlet > .extensions .extension.loading > .icon { display: none; } -.extensions-viewlet > .extensions .extension-container > .extension > .header > .details { +.extensions-viewlet > .extensions .extension > .details { flex: 1; - padding: 8px; + padding: 4px 0; overflow: hidden; } -.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .title > .name { +.extensions-viewlet > .extensions .extension > .details > .header { + display: flex; +} + +.extensions-viewlet > .extensions .extension > .details > .header > .name { font-weight: bold; } -.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .subtitle { +.extensions-viewlet > .extensions .extension > .details > .header > .version { + opacity: 0.6; + font-size: 80%; + padding-left: 6px; +} + +.extensions-viewlet > .extensions .extension > .details > .header > .author { + flex: 1; font-size: 90%; + text-align: right; + padding-left: 6px; } -.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > .subtitle > .author { - font-style: italic; -} - -.extensions-viewlet > .extensions .extension-container > .extension > .header > .details > div { +.extensions-viewlet > .extensions .extension .ellipsis { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; +} + +/*.extensions-viewlet > .extensions .extension > .details { width: 100%; -} - -.extensions-viewlet > .extensions .extension-container > .extension > .body { - display: none; -} - -/* List overrides */ - -.extensions-viewlet .monaco-list-row:hover { - background-color: transparent; -} - -.extensions-viewlet .monaco-list-row.selected { - background-color: transparent; - color: inherit; -} - -/* Themeing */ - -.vs-dark .extensions-viewlet > .extensions .extension-container > .extension { - background-color: #333333; - box-shadow: 2px 2px 5px rgba(0,0,0,.3); -} - -.vs-dark .extensions-viewlet > .extensions .extension-container > .extension:hover { - box-shadow: 2px 2px 5px rgba(0,0,0,.7); -} - -/* Selection */ - -.extensions-viewlet .monaco-list-row.selected .extension-container > .extension { - box-shadow: 2px 2px 5px rgba(0,0,0,.25); - background-color: #4FA7FF; - color: white; -} - -.vs-dark .extensions-viewlet .monaco-list-row.selected .extension-container > .extension { - box-shadow: 2px 2px 5px rgba(0,0,0,.7); - background-color: #0E639C; - color: white; -} \ No newline at end of file +}*/ \ No newline at end of file From f35fa2bb2a45983be320779fe9226522230e49f9 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 15 Jun 2016 11:00:16 +0200 Subject: [PATCH 038/126] list: useShadows options --- src/vs/base/browser/ui/list/listView.ts | 15 ++++++++++++--- src/vs/base/browser/ui/list/listWidget.ts | 12 +++++++++--- .../contrib/suggest/browser/suggestWidget.ts | 4 +++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index efaf86b1a4f..cf0b8fc2b91 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { toObject, assign } from 'vs/base/common/objects'; +import { toObject, assign, getOrDefault } from 'vs/base/common/objects'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Gesture } from 'vs/base/browser/touch'; import * as DOM from 'vs/base/browser/dom'; @@ -38,6 +38,14 @@ const MouseEventTypes = [ 'contextmenu' ]; +export interface IListViewOptions { + useShadows?: boolean; +} + +const DefaultOptions: IListViewOptions = { + useShadows: true +}; + export class ListView implements IDisposable { private items: IItem[]; @@ -56,7 +64,8 @@ export class ListView implements IDisposable { constructor( container: HTMLElement, private delegate: IDelegate, - renderers: IRenderer[] + renderers: IRenderer[], + options: IListViewOptions = DefaultOptions ) { this.items = []; this.itemId = 0; @@ -79,7 +88,7 @@ export class ListView implements IDisposable { canUseTranslate3d: false, horizontal: ScrollbarVisibility.Hidden, vertical: ScrollbarVisibility.Auto, - useShadows: false, + useShadows: getOrDefault(options, o => o.useShadows, DefaultOptions.useShadows), saveLastScrollTimeOnClassName: 'monaco-list-row' }); diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 00815a1a5c0..4dfb48f44b2 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -9,7 +9,7 @@ import { isNumber } from 'vs/base/common/types'; import * as DOM from 'vs/base/browser/dom'; import Event, { Emitter, mapEvent, EventBufferer } from 'vs/base/common/event'; import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list'; -import { ListView } from './listView'; +import { ListView, IListViewOptions } from './listView'; interface ITraitTemplateData { container: HTMLElement; @@ -146,6 +146,11 @@ class Controller implements IDisposable { } } +export interface IListOptions extends IListViewOptions { +} + +const DefaultOptions: IListOptions = {}; + export class List implements IDisposable { private static InstanceCount = 0; @@ -168,7 +173,8 @@ export class List implements IDisposable { constructor( container: HTMLElement, delegate: IDelegate, - renderers: IRenderer[] + renderers: IRenderer[], + options: IListOptions = DefaultOptions ) { this.focus = new FocusTrait(i => this.getElementId(i)); this.selection = new Trait('selected'); @@ -180,7 +186,7 @@ export class List implements IDisposable { return r; }); - this.view = new ListView(container, delegate, renderers); + this.view = new ListView(container, delegate, renderers, options); this.view.domNode.setAttribute('role', 'listbox'); this.controller = new Controller(this, this.view); } diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 8956509b1d3..a4ec74e26b9 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -364,7 +364,9 @@ export class SuggestWidget implements IContentWidget, IDisposable { let renderer: IRenderer = instantiationService.createInstance(Renderer, this, this.editor); this.delegate = new Delegate(() => this.list); - this.list = new List(this.listElement, this.delegate, [renderer]); + this.list = new List(this.listElement, this.delegate, [renderer], { + useShadows: false + }); this.toDispose = [ editor.onDidBlurEditorText(() => this.onEditorBlur()), From 41c4d49638de1bc50be115dbbde1884dc88979b3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 15 Jun 2016 17:44:07 +0200 Subject: [PATCH 039/126] css --- .../extensions/electron-browser/media/extensionsViewlet.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index d96250e257b..f16e30a372d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -10,7 +10,7 @@ .extensions-viewlet > .search { height: 38px; box-sizing: border-box; - padding: 5px 19px 5px 16px; + padding: 5px 9px 5px 16px; } .extensions-viewlet > .search > .search-box { From d5e4540b518aa386d4bbf372617b63eab8bd980f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 16:01:21 +0200 Subject: [PATCH 040/126] allow IO from shared process in dev --- src/bootstrap.js | 20 +++++++++++--------- src/vs/code/electron-main/main.ts | 2 +- src/vs/code/electron-main/sharedProcess.ts | 11 +++++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/bootstrap.js b/src/bootstrap.js index 093706562c6..b029d660f42 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -90,16 +90,18 @@ if (!!process.send && process.env.PIPE_LOGGING === 'true') { console.error = function () { safeSend({ type: '__$console', severity: 'error', arguments: safeStringify(arguments) }); }; } -// Let stdout, stderr and stdin be no-op streams. This prevents an issue where we would get an EBADF -// error when we are inside a forked process and this process tries to access those channels. -var stream = require('stream'); -var writable = new stream.Writable({ - write: function () { /* No OP */ } -}); +if (!process.env['VSCODE_ALLOW_IO']) { + // Let stdout, stderr and stdin be no-op streams. This prevents an issue where we would get an EBADF + // error when we are inside a forked process and this process tries to access those channels. + var stream = require('stream'); + var writable = new stream.Writable({ + write: function () { /* No OP */ } + }); -process.__defineGetter__('stdout', function() { return writable; }); -process.__defineGetter__('stderr', function() { return writable; }); -process.__defineGetter__('stdin', function() { return writable; }); + process.__defineGetter__('stdout', function() { return writable; }); + process.__defineGetter__('stderr', function() { return writable; }); + process.__defineGetter__('stdin', function() { return writable; }); +} // Handle uncaught exceptions process.on('uncaughtException', function (err) { diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 6b333959977..d089e91152b 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -108,7 +108,7 @@ function main(accessor: ServicesAccessor, ipcServer: Server, userEnv: IProcessEn process.env['VSCODE_SHARED_IPC_HOOK'] = envService.sharedIPCHandle; // Spawn shared process - const sharedProcess = instantiationService.invokeFunction(spawnSharedProcess); + const sharedProcess = spawnSharedProcess(!envService.isBuilt || envService.cliArgs.verboseLogging); // Make sure we associate the program with the app user model id // This will help Windows to associate the running program with diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index fcaa716732c..d6274c6c984 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -7,15 +7,18 @@ import * as cp from 'child_process'; import URI from 'vs/base/common/uri'; import { IDisposable } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; const boostrapPath = URI.parse(require.toUrl('bootstrap')).fsPath; -function _spawnSharedProcess(): cp.ChildProcess { +function _spawnSharedProcess(allowOutput: boolean): cp.ChildProcess { const env = assign({}, process.env, { AMD_ENTRYPOINT: 'vs/code/node/sharedProcessMain' }); + if (allowOutput) { + env['VSCODE_ALLOW_IO'] = 'true'; + } + const result = cp.fork(boostrapPath, ['--type=SharedProcess'], { env }); // handshake @@ -26,7 +29,7 @@ function _spawnSharedProcess(): cp.ChildProcess { let spawnCount = 0; -export function spawnSharedProcess(accessor: ServicesAccessor): IDisposable { +export function spawnSharedProcess(allowOutput: boolean): IDisposable { let child: cp.ChildProcess; const spawn = () => { @@ -34,7 +37,7 @@ export function spawnSharedProcess(accessor: ServicesAccessor): IDisposable { return; } - child = _spawnSharedProcess(); + child = _spawnSharedProcess(allowOutput); child.on('exit', spawn); }; From 9b90c12a410ad125d37c418261d22cb31ae69c7d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 16:17:17 +0200 Subject: [PATCH 041/126] remove extension quick open & status bar widget --- .../extensions.contribution.ts | 5 - .../electron-browser/extensionsQuickOpen.ts | 617 ------------------ .../electron-browser/extensionsWidgets.ts | 170 ----- .../extensionsWorkbenchExtension.ts | 50 +- src/vs/workbench/workbench.main.ts | 1 - 5 files changed, 1 insertion(+), 842 deletions(-) delete mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen.ts delete mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 6fe983768d0..7652935305b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -7,8 +7,6 @@ import 'vs/css!./media/extensions'; import { localize } from 'vs/nls'; import { Registry } from 'vs/platform/platform'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar'; -import { ExtensionsStatusbarItem } from 'vs/workbench/parts/extensions/electron-browser/extensionsWidgets'; import { IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel, ExtensionsChannelId } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; @@ -41,9 +39,6 @@ registerSingleton(IExtensionTipsService, ExtensionTipsService); Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(ExtensionsWorkbenchExtension); -Registry.as(StatusbarExtensions.Statusbar) - .registerStatusbarItem(new StatusbarItemDescriptor(ExtensionsStatusbarItem, StatusbarAlignment.LEFT,10000)); - Registry.as(OutputExtensions.OutputChannels) .registerChannel(ExtensionsChannelId, ExtensionsLabel); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen.ts deleted file mode 100644 index 87bc1a3bcd5..00000000000 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen.ts +++ /dev/null @@ -1,617 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import nls = require('vs/nls'); -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { isNumber } from 'vs/base/common/types'; -import { PagedModel, mapPager } from 'vs/base/common/paging'; -import { ThrottledDelayer } from 'vs/base/common/async'; -import * as dom from 'vs/base/browser/dom'; -import Severity from 'vs/base/common/severity'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { IAutoFocus, Mode, IModel, IDataSource, IRenderer, IRunner, IEntryRunContext, IAccessiblityProvider } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenPagedModel, IPagedRenderer } from 'vs/base/parts/quickopen/common/quickOpenPaging'; -import { matchesContiguousSubString } from 'vs/base/common/filters'; -import { QuickOpenHandler } from 'vs/workbench/browser/quickopen'; -import { IHighlight } from 'vs/base/parts/quickopen/browser/quickOpenModel'; -import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, IExtension, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { InstallAction, UninstallAction } from 'vs/workbench/parts/extensions/electron-browser/extensionsActions'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; -import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; -import { Action } from 'vs/base/common/actions'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { shell } from 'electron'; -import { extensionEquals, getOutdatedExtensions } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; - -const $ = dom.emmet; - -const InstallLabel = nls.localize('install', "Install Extension"); -const UpdateLabel = nls.localize('update', "Update Extension"); - -export interface IHighlights { - id: IHighlight[]; - name: IHighlight[]; - displayName: IHighlight[]; - description: IHighlight[]; -} - -export enum ExtensionState { - Uninstalled, - Installed, - Outdated -} - -export interface IExtensionEntry { - extension: IExtension; - highlights: IHighlights; - state: ExtensionState; -} - -interface ITemplateData { - root: HTMLElement; - displayName: HighlightedLabel; - version: HTMLElement; - installCount: HTMLElement; - installCountLabel: HTMLElement; - author: HTMLElement; - actionbar: ActionBar; - description: HighlightedLabel; - disposables: IDisposable[]; -} - -function getHighlights(input: string, extension: IExtension, nullIfEmpty = true): IHighlights { - const id = matchesContiguousSubString(input, `${ extension.publisher }.${ extension.name }`) || []; - const name = matchesContiguousSubString(input, extension.name) || []; - const displayName = matchesContiguousSubString(input, extension.displayName) || []; - const description = matchesContiguousSubString(input, extension.description) || []; - - if (nullIfEmpty && !id.length && !name.length && !displayName.length && !description.length) { - return null; - } - - return { id, name, displayName, description }; -} - -function extensionEntryCompare(one: IExtensionEntry, other: IExtensionEntry): number { - const oneInstallCount = one.extension.galleryInformation ? one.extension.galleryInformation.installCount : 0; - const otherInstallCount = other.extension.galleryInformation ? other.extension.galleryInformation.installCount : 0; - const diff = otherInstallCount - oneInstallCount; - - if (diff !== 0) { - return diff; - } - - return one.extension.displayName.localeCompare(other.extension.displayName); -} - -class OpenLicenseAction extends Action { - - constructor( - @IWorkspaceContextService private contextService: IWorkspaceContextService - ) { - super('extensions.open-license', nls.localize('license', "License"), '', true); - } - - public run(extension: IExtension): TPromise { - const url = `${ this.contextService.getConfiguration().env.extensionsGallery.itemUrl }/${ extension.publisher }.${ extension.name }/license`; - shell.openExternal(url); - return TPromise.as(null); - } -} - -class OpenInGalleryAction extends Action { - - constructor( - private promptToInstall: boolean, - @IMessageService protected messageService: IMessageService, - @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IInstantiationService protected instantiationService: IInstantiationService - ) { - super('extensions.open-in-gallery', nls.localize('readme', "Readme"), '', true); - } - - public run(extension: IExtension): TPromise { - const url = `${this.contextService.getConfiguration().env.extensionsGallery.itemUrl}/${ extension.publisher }.${ extension.name }`; - shell.openExternal(url); - - if (!this.promptToInstall) { - return TPromise.as(null); - } - - const hideMessage = this.messageService.show(Severity.Info, { - message: nls.localize('installPrompt', "Would you like to install '{0}'?", extension.displayName), - actions: [ - new Action('cancelaction', nls.localize('cancel', 'Cancel')), - new Action('installNow', nls.localize('installNow', 'Install Now'), null, true, () => { - hideMessage(); - - const hideInstallMessage = this.messageService.show(Severity.Info, nls.localize('nowInstalling', "'{0}' is being installed...", extension.displayName)); - - const action = this.instantiationService.createInstance(InstallAction, ''); - return action.run(extension).then(r => { - hideInstallMessage(); - return TPromise.as(r); - }, e => { - hideInstallMessage(); - return TPromise.wrapError(e); - }); - }) - ] - }); - - return TPromise.as(null); - } -} - -class InstallRunner implements IRunner { - - private action: InstallAction; - - constructor( - @IInstantiationService private instantiationService: IInstantiationService - ) {} - - run(entry: IExtensionEntry, mode: Mode, context: IEntryRunContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - if (entry.state === ExtensionState.Installed) { - return false; - } - - if (!this.action) { - this.action = this.instantiationService.createInstance(InstallAction, InstallLabel); - } - - this.action.run(entry.extension).done(null, onUnexpectedError); - return true; - } -} - -class AccessibilityProvider implements IAccessiblityProvider { - - public getAriaLabel(entry: IExtensionEntry): string { - return nls.localize('extensionAriaLabel', "{0}, {1}, extensions picker", entry.extension.displayName, entry.extension.description); - } -} - -class Renderer implements IPagedRenderer { - - constructor( - @IInstantiationService private instantiationService: IInstantiationService, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService - ) {} - - getHeight(entry: IExtensionEntry): number { - return 48; - } - - getTemplateId(entry: IExtensionEntry): string { - return 'extension'; - } - - renderTemplate(templateId: string, container: HTMLElement): ITemplateData { - // Important to preserve order here. - const root = dom.append(container, $('.extension')); - const firstRow = dom.append(root, $('.row')); - const secondRow = dom.append(root, $('.row')); - const published = dom.append(firstRow, $('.published')); - const displayName = new HighlightedLabel(dom.append(firstRow, $('span.name'))); - const installCount = dom.append(firstRow, $('span.install')); - dom.append(installCount, $('span.octicon.octicon-cloud-download')); - const installCountLabel = dom.append(installCount, $('span.installCount')); - const version = dom.append(published, $('span.version')); - const author = dom.append(published, $('span.author')); - - return { - root, - author, - displayName, - version, - installCount, - installCountLabel, - actionbar: new ActionBar(dom.append(secondRow, $('.actions'))), - description: new HighlightedLabel(dom.append(secondRow, $('span.description'))), - disposables: [] - }; - } - - renderPlaceholder(index: number, templateId: string, data: ITemplateData): void { - dom.addClass(data.root, 'loading'); - - data.author.textContent = nls.localize('author', 'Author'); - data.displayName.set(nls.localize('name', 'Name')); - data.version.textContent = '0.0.1'; - data.installCount.style.display = 'none'; - data.installCountLabel.textContent = ''; - data.actionbar.clear(); - data.description.set(nls.localize('description', 'Description')); - data.disposables = dispose(data.disposables); - } - - renderElement(entry: IExtensionEntry, templateId: string, data: ITemplateData): void { - dom.removeClass(data.root, 'loading'); - - const extension = entry.extension; - const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; - const installCount = extension.galleryInformation ? extension.galleryInformation.installCount : null; - const actionOptions = { icon: true, label: false }; - - const updateActions = () => { - data.actionbar.clear(); - - if (entry.extension.galleryInformation) { - data.actionbar.push(this.instantiationService.createInstance(OpenInGalleryAction, entry.state === ExtensionState.Uninstalled), { label: true, icon: false }); - data.actionbar.push(this.instantiationService.createInstance(OpenLicenseAction), { label: true, icon: false }); - } - - switch (entry.state) { - case ExtensionState.Uninstalled: - if (entry.extension.galleryInformation) { - data.actionbar.push(this.instantiationService.createInstance(InstallAction, InstallLabel), actionOptions); - } - break; - case ExtensionState.Installed: - data.actionbar.push(this.instantiationService.createInstance(UninstallAction), actionOptions); - break; - case ExtensionState.Outdated: - data.actionbar.push(this.instantiationService.createInstance(UninstallAction), actionOptions); - data.actionbar.push(this.instantiationService.createInstance(InstallAction, UpdateLabel), actionOptions); - break; - } - }; - - const onExtensionStateChange = (e: IExtension, state: ExtensionState) => { - if (extensionEquals(e, extension)) { - entry.state = state; - updateActions(); - } - }; - - data.actionbar.context = extension; - updateActions(); - - data.disposables = dispose(data.disposables); - data.disposables.push(this.extensionManagementService.onDidInstallExtension(e => onExtensionStateChange(e.extension, ExtensionState.Installed))); - data.disposables.push(this.extensionManagementService.onDidUninstallExtension(e => onExtensionStateChange(e, ExtensionState.Uninstalled))); - - data.displayName.set(extension.displayName, entry.highlights.displayName); - data.displayName.element.title = extension.name; - data.version.textContent = extension.version; - - if (isNumber(installCount)) { - data.installCount.style.display = 'inline'; - data.installCountLabel.textContent = String(installCount); - - if (!installCount) { - data.installCount.title = nls.localize('installCountZero', "{0} wasn't downloaded yet.", extension.displayName); - } else if (installCount === 1) { - data.installCount.title = nls.localize('installCountOne', "{0} was downloaded once.", extension.displayName); - } else { - data.installCount.title = nls.localize('installCountMultiple', "{0} was downloaded {1} times.", extension.displayName, installCount); - } - } else { - data.installCount.style.display = 'none'; - data.installCountLabel.textContent = ''; - } - - data.author.textContent = publisher; - data.description.set(extension.description, entry.highlights.description); - data.description.element.title = extension.description; - } - - disposeTemplate(templateId: string, data: ITemplateData): void { - data.displayName.dispose(); - data.description.dispose(); - data.disposables = dispose(data.disposables); - } -} - -class DataSource implements IDataSource { - - getId(entry: IExtensionEntry): string { - const extension = entry.extension; - - if (!extension) { - throw new Error(`Not an extension entry. Found ${ Object.keys(entry).slice(5) },... instead.`); - } - - if (extension.galleryInformation) { - return `${ extension.galleryInformation.id }-${ extension.version }`; - } - - return `local@${ extension.publisher }.${ extension.name }-${ extension.version }@${ extension.path || '' }`; - } - - getLabel(entry: IExtensionEntry): string { - return entry.extension.name; - } -} - -class LocalExtensionsModel implements IModel { - - public dataSource = new DataSource(); - public renderer: IRenderer; - public accessibilityProvider: IAccessiblityProvider = new AccessibilityProvider(); - public runner = { run: () => false }; - public entries: IExtensionEntry[]; - - constructor( - private installedExtensions: IExtension[], - private outdatedExtensions: IExtension[], - @IInstantiationService instantiationService: IInstantiationService - ) { - this.renderer = instantiationService.createInstance(Renderer); - this.entries = []; - } - - public set input(input: string) { - this.entries = this.installedExtensions - .map(extension => ({ extension, highlights: getHighlights(input.trim(), extension) })) - .filter(({ highlights }) => !!highlights) - .map(({ extension, highlights }: { extension: IExtension, highlights: IHighlights }) => { - const [outdatedExt] = this.outdatedExtensions.filter(outdatedExt => extensionEquals(outdatedExt, extension)); - - return { - extension, - highlights, - state: outdatedExt - ? ExtensionState.Outdated - : ExtensionState.Installed - }; - }) - .sort(extensionEntryCompare); - } -} - -export class LocalExtensionsHandler extends QuickOpenHandler { - - private modelPromise: TPromise; - - constructor( - @IInstantiationService private instantiationService: IInstantiationService, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IExtensionGalleryService private galleryService: IExtensionGalleryService - ) { - super(); - this.modelPromise = null; - } - - public getAriaLabel(): string { - return nls.localize('localExtensionsHandlerAriaLabel', "Type to narrow down the list of installed extensions"); - } - - getResults(input: string): TPromise> { - if (!this.modelPromise) { - this.modelPromise = TPromise.join([this.extensionManagementService.getInstalled(), - getOutdatedExtensions(this.extensionManagementService, this.galleryService)]) - .then(result => this.instantiationService.createInstance(LocalExtensionsModel, result[0], result[1])); - } - - return this.modelPromise.then(model => { - model.input = input; - return model; - }); - } - - getEmptyLabel(input: string): string { - return nls.localize('noExtensionsInstalled', "No extensions found"); - } - - getAutoFocus(searchValue: string): IAutoFocus { - return { autoFocusFirstEntry: true }; - } - - onClose(canceled: boolean): void { - this.modelPromise = null; - } -} - -export class GalleryExtensionsHandler extends QuickOpenHandler { - - private delayer: ThrottledDelayer; - - constructor( - @IInstantiationService private instantiationService: IInstantiationService, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @ITelemetryService private telemetryService: ITelemetryService - ) { - super(); - this.delayer = new ThrottledDelayer(500); - } - - public getAriaLabel(): string { - return nls.localize('galleryExtensionsHandlerAriaLabel', "Type to narrow down the list of extensions from the gallery"); - } - - getResults(text: string): TPromise> { - return this.extensionManagementService.getInstalled().then(localExtensions => { - return this.delayer.trigger(() => this.galleryService.query({ text })).then((result: IQueryResult) => { - const pager = mapPager(result, extension => { - const [local] = localExtensions.filter(local => extensionEquals(local, extension)); - - return { - extension, - highlights: getHighlights(text.trim(), extension, false), - state: local - ? (local.version === extension.version ? ExtensionState.Installed : ExtensionState.Outdated) - : ExtensionState.Uninstalled - }; - }); - - return new QuickOpenPagedModel( - new PagedModel(pager), - new DataSource(), - this.instantiationService.createInstance(Renderer), - this.instantiationService.createInstance(InstallRunner) - ); - }); - }); - } - - getEmptyLabel(input: string): string { - return nls.localize('noExtensionsToInstall', "No extensions found"); - } - - getAutoFocus(searchValue: string): IAutoFocus { - return { autoFocusFirstEntry: true }; - } -} - -class OutdatedExtensionsModel implements IModel { - - public dataSource = new DataSource(); - public accessibilityProvider: IAccessiblityProvider = new AccessibilityProvider(); - public renderer: IRenderer; - public runner: IRunner; - public entries: IExtensionEntry[]; - - constructor( - private outdatedExtensions: IExtension[], - @IInstantiationService instantiationService: IInstantiationService - ) { - this.renderer = instantiationService.createInstance(Renderer); - this.runner = instantiationService.createInstance(InstallRunner); - this.entries = []; - } - - public set input(input: string) { - this.entries = this.outdatedExtensions - .map(extension => ({ extension, highlights: getHighlights(input.trim(), extension) })) - .filter(({ highlights }) => !!highlights) - .map(({ extension, highlights }) => ({ - extension, - highlights, - state: ExtensionState.Outdated - })) - .sort(extensionEntryCompare); - } -} - -export class OutdatedExtensionsHandler extends QuickOpenHandler { - - private modelPromise: TPromise; - - constructor( - @IInstantiationService private instantiationService: IInstantiationService, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @ITelemetryService private telemetryService: ITelemetryService - ) { - super(); - } - - public getAriaLabel(): string { - return nls.localize('outdatedExtensionsHandlerAriaLabel', "Type to narrow down the list of outdated extensions"); - } - - getResults(input: string): TPromise> { - if (!this.modelPromise) { - this.telemetryService.publicLog('extensionGallery:open'); - - this.modelPromise = getOutdatedExtensions(this.extensionManagementService, this.galleryService) - .then(outdated => this.instantiationService.createInstance(OutdatedExtensionsModel, outdated)); - } - - return this.modelPromise.then(model => { - model.input = input; - return model; - }); - } - - onClose(canceled: boolean): void { - this.modelPromise = null; - } - - getEmptyLabel(input: string): string { - return nls.localize('noOutdatedExtensions', "No outdated extensions found"); - } - - getAutoFocus(searchValue: string): IAutoFocus { - return { autoFocusFirstEntry: true }; - } -} - - -class SuggestedExtensionsModel implements IModel { - - public dataSource = new DataSource(); - public renderer: IRenderer; - public runner: IRunner; - public entries: IExtensionEntry[]; - - constructor( - private suggestedExtensions: IExtension[], - private localExtensions: IExtension[], - @IInstantiationService instantiationService: IInstantiationService - ) { - this.renderer = instantiationService.createInstance(Renderer); - this.runner = instantiationService.createInstance(InstallRunner); - this.entries = []; - } - - public set input(input: string) { - this.entries = this.suggestedExtensions - .map(extension => ({ extension, highlights: getHighlights(input.trim(), extension) })) - .filter(({ extension, highlights }) => { - const local = this.localExtensions.filter(local => extensionEquals(local, extension))[0]; - return !local && !!highlights; - }) - .map(({ extension, highlights }: { extension: IExtension, highlights: IHighlights }) => { - return { - extension, - highlights, - state: ExtensionState.Uninstalled - }; - }) - .sort(extensionEntryCompare); - } -} - - -export class SuggestedExtensionHandler extends QuickOpenHandler { - - private modelPromise: TPromise; - - constructor( - @IExtensionTipsService private extensionTipsService: IExtensionTipsService, - @IInstantiationService private instantiationService: IInstantiationService, - @ITelemetryService private telemetryService: ITelemetryService, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService - ) { - super(); - } - - getResults(input: string): TPromise> { - if (!this.modelPromise) { - this.telemetryService.publicLog('extensionRecommendations:open'); - this.modelPromise = TPromise.join([this.extensionTipsService.getRecommendations(), this.extensionManagementService.getInstalled()]) - .then(result => this.instantiationService.createInstance(SuggestedExtensionsModel, result[0], result[1])); - } - - return this.modelPromise.then(model => { - model.input = input; - return model; - }); - } - - onClose(canceled: boolean): void { - this.modelPromise = null; - } - - getEmptyLabel(input: string): string { - return nls.localize('noRecommendedExtensions', "No recommended extensions"); - } - - getAutoFocus(searchValue: string): IAutoFocus { - return { autoFocusFirstEntry: true }; - } -} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts deleted file mode 100644 index 2e3255c4f95..00000000000 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts +++ /dev/null @@ -1,170 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import Severity from 'vs/base/common/severity'; -import { ThrottledDelayer } from 'vs/base/common/async'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { emmet as $, append, toggleClass } from 'vs/base/browser/dom'; -import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { onUnexpectedPromiseError } from 'vs/base/common/errors'; -import { assign } from 'vs/base/common/objects'; -import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; -import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import { IExtensionService, IMessage } from 'vs/platform/extensions/common/extensions'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionManagementService, IExtensionGalleryService, ExtensionsLabel, ExtensionsChannelId, IExtension, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; -import { getOutdatedExtensions } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; - -interface IState { - errors: IMessage[]; - installing: IExtensionManifest[]; - outdated: IExtension[]; -} - -const InitialState: IState = { - errors: [], - installing: [], - outdated: [] -}; - -function extensionEquals(one: IExtensionManifest, other: IExtensionManifest): boolean { - return one.publisher === other.publisher && one.name === other.name; -} - -const OutdatedPeriod = 12 * 60 * 60 * 1000; // every 12 hours - -export class ExtensionsStatusbarItem implements IStatusbarItem { - - private domNode: HTMLElement; - private state: IState = InitialState; - private outdatedDelayer = new ThrottledDelayer(OutdatedPeriod); - - constructor( - @IExtensionService private extensionService: IExtensionService, - @IOutputService private outputService: IOutputService, - @IExtensionManagementService protected extensionManagementService: IExtensionManagementService, - @IExtensionGalleryService protected extensionGalleryService: IExtensionGalleryService, - @IInstantiationService protected instantiationService: IInstantiationService, - @IQuickOpenService protected quickOpenService: IQuickOpenService, - @ITelemetryService protected telemetrService: ITelemetryService - ) {} - - render(container: HTMLElement): IDisposable { - this.domNode = append(container, $('a.extensions-statusbar')); - append(this.domNode, $('.icon')); - this.domNode.onclick = () => this.onClick(); - - this.checkErrors(); - this.checkOutdated(); - - const disposables = []; - this.extensionManagementService.onInstallExtension(this.onInstallExtension, this, disposables); - this.extensionManagementService.onDidInstallExtension(this.onDidInstallExtension, this, disposables); - this.extensionManagementService.onDidUninstallExtension(this.onDidUninstallExtension, this, disposables); - - return combinedDisposable(disposables); - } - - private updateState(obj: any): void { - this.state = assign(this.state, obj); - this.onStateChange(); - } - - private get hasErrors() { return this.state.errors.length > 0; } - private get isInstalling() { return this.state.installing.length > 0; } - private get hasUpdates() { return this.state.outdated.length > 0; } - - private onStateChange(): void { - toggleClass(this.domNode, 'has-errors', this.hasErrors); - toggleClass(this.domNode, 'is-installing', !this.hasErrors && this.isInstalling); - toggleClass(this.domNode, 'has-updates', !this.hasErrors && !this.isInstalling && this.hasUpdates); - - if (this.hasErrors) { - const singular = nls.localize('oneIssue', "Extensions (1 issue)"); - const plural = nls.localize('multipleIssues', "Extensions ({0} issues)", this.state.errors.length); - this.domNode.title = this.state.errors.length > 1 ? plural : singular; - } else if (this.isInstalling) { - this.domNode.title = nls.localize('extensionsInstalling', "Extensions ({0} installing...)", this.state.installing.length); - } else if (this.hasUpdates) { - const singular = nls.localize('oneUpdate', "Extensions (1 update available)"); - const plural = nls.localize('multipleUpdates', "Extensions ({0} updates available)", this.state.outdated.length); - this.domNode.title = this.state.outdated.length > 1 ? plural : singular; - } else { - this.domNode.title = nls.localize('extensions', "Extensions"); - } - } - - private onClick(): void { - if (this.hasErrors) { - this.telemetrService.publicLog('extensionWidgetClick', {mode : 'hasErrors'}); - this.showErrors(this.state.errors); - this.updateState({ errors: [] }); - } else if (this.hasUpdates) { - this.telemetrService.publicLog('extensionWidgetClick', {mode : 'hasUpdate'}); - this.quickOpenService.show(`ext update `); - } else { - this.telemetrService.publicLog('extensionWidgetClick', {mode : 'none'}); - this.quickOpenService.show(`>${ExtensionsLabel}: `); - } - } - - private showErrors(errors: IMessage[]): void { - const promise = onUnexpectedPromiseError(this.extensionManagementService.getInstalled()); - promise.done(installed => { - errors.forEach(m => { - const extension = installed.filter(ext => ext.path === m.source).pop(); - const name = extension && extension.name; - const message = name ? `${ name }: ${ m.message }` : m.message; - - const outputChannel = this.outputService.getChannel(ExtensionsChannelId); - outputChannel.append(message); - outputChannel.show(true); - }); - }); - } - - private onInstallExtension(manifest: IExtensionManifest): void { - const installing = [...this.state.installing, manifest]; - this.updateState({ installing }); - } - - private onDidInstallExtension({ extension }: { extension: IExtension; }): void { - const installing = this.state.installing - .filter(e => !extensionEquals(extension, e)); - this.updateState({ installing }); - this.outdatedDelayer.trigger(() => this.checkOutdated(), 0); - } - - private onDidUninstallExtension(): void { - this.outdatedDelayer.trigger(() => this.checkOutdated(), 0); - } - - private checkErrors(): void { - const promise = onUnexpectedPromiseError(this.extensionService.onReady()); - promise.done(() => { - const status = this.extensionService.getExtensionsStatus(); - const errors = Object.keys(status) - .map(k => status[k].messages) - .reduce((r, m) => r.concat(m), []) - .filter(m => m.type > Severity.Info); - - this.updateState({ errors }); - }); - } - - private checkOutdated(): TPromise { - return getOutdatedExtensions(this.extensionManagementService, this.extensionGalleryService) - .then(null, _ => []) // ignore errors - .then(outdated => { - this.updateState({ outdated }); - - // repeat this later - this.outdatedDelayer.trigger(() => this.checkOutdated()); - }); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts index 1fdb6ab2337..74b0fa6de43 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts @@ -16,8 +16,7 @@ import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import wbaregistry = require('vs/workbench/common/actionRegistry'); import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ListExtensionsAction, InstallExtensionAction, ListOutdatedExtensionsAction, ListSuggestedExtensionsAction } from './extensionsActions'; -import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; +import { ListExtensionsAction } from './extensionsActions'; import {ipcRenderer as ipc} from 'electron'; interface IInstallExtensionsRequest { @@ -44,53 +43,6 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution { const actionRegistry = ( platform.Registry.as(wbaregistry.Extensions.WorkbenchActions)); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel); - - (platform.Registry.as(Extensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen', - 'LocalExtensionsHandler', - 'ext ', - nls.localize('localExtensionsCommands', "Show Local Extensions") - ) - ); - - if (galleryService.isEnabled()) { - - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InstallExtensionAction, InstallExtensionAction.ID, InstallExtensionAction.LABEL), 'Extensions: Install Extension', ExtensionsLabel); - - (platform.Registry.as(Extensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen', - 'GalleryExtensionsHandler', - 'ext install ', - nls.localize('galleryExtensionsCommands', "Install Gallery Extensions"), - true - ) - ); - - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListOutdatedExtensionsAction, ListOutdatedExtensionsAction.ID, ListOutdatedExtensionsAction.LABEL), 'Extensions: Show Outdated Extensions', ExtensionsLabel); - - (platform.Registry.as(Extensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen', - 'OutdatedExtensionsHandler', - 'ext update ', - nls.localize('outdatedExtensionsCommands', "Update Outdated Extensions") - ) - ); - - // add extension tips services - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListSuggestedExtensionsAction, ListSuggestedExtensionsAction.ID, ListSuggestedExtensionsAction.LABEL), 'Extensions: Show Extension Recommendations', ExtensionsLabel); - - (platform.Registry.as(Extensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen', - 'SuggestedExtensionHandler', - 'ext recommend ', - nls.localize('suggestedExtensionsCommands', "Show Extension Recommendations") - ) - ); - } } private registerListeners(): void { diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 344337be8b1..c111ac10d6c 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -44,7 +44,6 @@ import 'vs/workbench/parts/markers/markers.contribution'; import 'vs/workbench/parts/html/browser/html.contribution'; import 'vs/workbench/parts/extensions/electron-browser/extensions.contribution'; -import 'vs/workbench/parts/extensions/electron-browser/extensionsQuickOpen'; import 'vs/workbench/parts/output/browser/output.contribution'; From 12ba6a2a6d6032070d2d401f703a344a70f7d3d7 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 17:26:01 +0200 Subject: [PATCH 042/126] simplify extension events --- src/vs/code/node/cliProcessMain.ts | 2 +- .../common/extensionManagement.ts | 15 ++- .../common/extensionManagementIpc.ts | 24 ++-- .../node/extensionManagementService.ts | 108 +++++++++--------- 4 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 08c16cc57a3..e3f53fd1bfd 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -94,7 +94,7 @@ class Main { console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); console.log(localize('installing', "Installing...")); - return this.extensionManagementService.install(extension).then(extension => { + return this.extensionManagementService.install(extension).then(() => { console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version)); }); }); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index cceece90501..c9406437cb8 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -66,15 +66,18 @@ export interface IExtensionGalleryService { query(options?: IQueryOptions): TPromise; } +export type DidInstallExtensionEvent = { id: string; error?: Error; }; + export interface IExtensionManagementService { serviceId: ServiceIdentifier; - onInstallExtension: Event; - onDidInstallExtension: Event<{ extension: IExtension; error?: Error; }>; - onUninstallExtension: Event; - onDidUninstallExtension: Event; - install(extension: IExtension): TPromise; - install(zipPath: string): TPromise; + onInstallExtension: Event; + onDidInstallExtension: Event; + onUninstallExtension: Event; + onDidUninstallExtension: Event; + + install(extension: IExtension): TPromise; + install(zipPath: string): TPromise; uninstall(extension: IExtension): TPromise; getInstalled(includeDuplicateVersions?: boolean): TPromise; } diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index debb987fea1..7863dddce0b 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, IExtension, IExtensionManifest } from './extensionManagement'; +import { IExtensionManagementService, IExtension, DidInstallExtensionEvent } from './extensionManagement'; import Event from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -44,21 +44,21 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer constructor(private channel: IExtensionManagementChannel) { } - private _onInstallExtension = eventFromCall(this.channel, 'event:onInstallExtension'); - get onInstallExtension(): Event { return this._onInstallExtension; } + private _onInstallExtension = eventFromCall(this.channel, 'event:onInstallExtension'); + get onInstallExtension(): Event { return this._onInstallExtension; } - private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); - get onDidInstallExtension(): Event<{ extension: IExtension; error?: Error; }> { return this._onDidInstallExtension; } + private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); + get onDidInstallExtension(): Event { return this._onDidInstallExtension; } - private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); - get onUninstallExtension(): Event { return this._onUninstallExtension; } + private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); + get onUninstallExtension(): Event { return this._onUninstallExtension; } - private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); - get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } + private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); + get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } - install(extension: IExtension): TPromise; - install(zipPath: string): TPromise; - install(arg: any): TPromise { + install(extension: IExtension): TPromise; + install(zipPath: string): TPromise; + install(arg: any): TPromise { return this.channel.call('install', arg); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 029f959417e..65bba93150d 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -16,7 +16,6 @@ import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; import { IExtensionManagementService, IExtension, IExtensionManifest, IGalleryMetadata, IGalleryVersion } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -95,17 +94,17 @@ export class ExtensionManagementService implements IExtensionManagementService { private obsoleteFileLimiter: Limiter; private disposables: IDisposable[]; - private _onInstallExtension = new Emitter(); - onInstallExtension: Event = this._onInstallExtension.event; + private _onInstallExtension = new Emitter(); + onInstallExtension: Event = this._onInstallExtension.event; - private _onDidInstallExtension = new Emitter<{ extension: IExtension; isUpdate: boolean; error?: Error; }>(); - onDidInstallExtension: Event<{ extension: IExtension; isUpdate: boolean; error?: Error; }> = this._onDidInstallExtension.event; + private _onDidInstallExtension = new Emitter<{ id: string; error?: Error; }>(); + onDidInstallExtension: Event<{ id: string; error?: Error; }> = this._onDidInstallExtension.event; - private _onUninstallExtension = new Emitter(); - onUninstallExtension: Event = this._onUninstallExtension.event; + private _onUninstallExtension = new Emitter(); + onUninstallExtension: Event = this._onUninstallExtension.event; - private _onDidUninstallExtension = new Emitter(); - onDidUninstallExtension: Event = this._onDidUninstallExtension.event; + private _onDidUninstallExtension = new Emitter(); + onDidUninstallExtension: Event = this._onDidUninstallExtension.event; constructor( @IEnvironmentService private environmentService: IEnvironmentService, @@ -115,21 +114,21 @@ export class ExtensionManagementService implements IExtensionManagementService { this.obsoletePath = path.join(this.extensionsPath, '.obsolete'); this.obsoleteFileLimiter = new Limiter(1); - this.disposables = [ - this.onDidInstallExtension(({ extension, isUpdate, error }) => telemetryService.publicLog( - isUpdate ? 'extensionGallery2:update' : 'extensionGallery2:install', - assign(getTelemetryData(extension), { success: !error }) - )), - this.onDidUninstallExtension(extension => telemetryService.publicLog( - 'extensionGallery2:uninstall', - assign(getTelemetryData(extension), { success: true }) - )) - ]; + // this.disposables = [ + // this.onDidInstallExtension(({ extension, isUpdate, error }) => telemetryService.publicLog( + // isUpdate ? 'extensionGallery2:update' : 'extensionGallery2:install', + // assign(getTelemetryData(extension), { success: !error }) + // )), + // this.onDidUninstallExtension(extension => telemetryService.publicLog( + // 'extensionGallery2:uninstall', + // assign(getTelemetryData(extension), { success: true }) + // )) + // ]; } - install(extension: IExtension): TPromise; - install(zipPath: string): TPromise; - install(arg: any): TPromise { + install(extension: IExtension): TPromise; + install(zipPath: string): TPromise; + install(arg: any): TPromise { if (types.isString(arg)) { return this.installFromZip(arg); } @@ -137,43 +136,40 @@ export class ExtensionManagementService implements IExtensionManagementService { const extension = arg as IExtension; return this.isObsolete(extension).then(obsolete => { if (obsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.name))); + return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.name))); } return this.installFromGallery(arg); }); } - private installFromGallery(extension: IExtension): TPromise { + private installFromGallery(extension: IExtension): TPromise { + const id = getExtensionId(extension); const galleryInformation = extension.galleryInformation; if (!galleryInformation) { - return TPromise.wrapError(new Error(nls.localize('missingGalleryInformation', "Gallery information is missing"))); + return TPromise.wrapError(new Error(nls.localize('missingGalleryInformation', "Gallery information is missing"))); } - this._onInstallExtension.fire(extension); + this._onInstallExtension.fire(id); return this.getLastValidExtensionVersion(extension, extension.galleryInformation.versions).then(versionInfo => { - return this.getInstalled() - .then(installed => installed.some(e => extensionEquals(e, extension))) - .then(isUpdate => { - const version = versionInfo.version; - const url = versionInfo.downloadUrl; - const headers = versionInfo.downloadHeaders; - const zipPath = path.join(tmpdir(), galleryInformation.id); - const extensionPath = path.join(this.extensionsPath, getExtensionId(extension, version)); - const manifestPath = path.join(extensionPath, 'package.json'); + const version = versionInfo.version; + const url = versionInfo.downloadUrl; + const headers = versionInfo.downloadHeaders; + const zipPath = path.join(tmpdir(), galleryInformation.id); + const extensionPath = path.join(this.extensionsPath, getExtensionId(extension, version)); + const manifestPath = path.join(extensionPath, 'package.json'); - return this.request(url) - .then(opts => assign(opts, { headers })) - .then(opts => download(zipPath, opts)) - .then(() => validate(zipPath, extension, version)) - .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest)) - .then(manifest => assign({ __metadata: galleryInformation }, manifest)) - .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) - .then(() => { this._onDidInstallExtension.fire({ extension, isUpdate }); return extension; }) - .then(null, error => { this._onDidInstallExtension.fire({ extension, isUpdate, error }); return TPromise.wrapError(error); }); - }); + return this.request(url) + .then(opts => assign(opts, { headers })) + .then(opts => download(zipPath, opts)) + .then(() => validate(zipPath, extension, version)) + .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest)) + .then(manifest => assign({ __metadata: galleryInformation }, manifest)) + .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => this._onDidInstallExtension.fire({ id })) + .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); } @@ -200,32 +196,30 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private installFromZip(zipPath: string): TPromise { + private installFromZip(zipPath: string): TPromise { return validate(zipPath).then(manifest => { + const id = getExtensionId(manifest); const extensionPath = path.join(this.extensionsPath, getExtensionId(manifest)); - this._onInstallExtension.fire(manifest); + this._onInstallExtension.fire(id); - return this.getInstalled() - .then(installed => installed.some(e => extensionEquals(e, manifest))) - .then(isUpdate => { - - return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) - .then(() => createExtension(manifest, ( manifest).__metadata, extensionPath)) - .then(extension => { this._onDidInstallExtension.fire({ extension, isUpdate }); return extension; }); - }); + return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) + .then(() => createExtension(manifest, ( manifest).__metadata, extensionPath)) + .then(extension => this._onDidInstallExtension.fire({ id })) + .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); } uninstall(extension: IExtension): TPromise { const extensionPath = extension.path || path.join(this.extensionsPath, getExtensionId(extension)); + const id = getExtensionId(extension); return pfs.exists(extensionPath) .then(exists => exists ? null : Promise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) - .then(() => this._onUninstallExtension.fire(extension)) + .then(() => this._onUninstallExtension.fire(id)) .then(() => this.setObsolete(extension)) .then(() => pfs.rimraf(extensionPath)) .then(() => this.unsetObsolete(extension)) - .then(() => this._onDidUninstallExtension.fire(extension)); + .then(() => this._onDidUninstallExtension.fire(id)); } getInstalled(includeDuplicateVersions: boolean = false): TPromise { From f5cbb9fe63369047449c930b87153caf3e6ed7ce Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 18:13:17 +0200 Subject: [PATCH 043/126] cleanup IGalleryExtension --- src/vs/code/node/cliProcessMain.ts | 4 +- .../common/extensionManagement.ts | 16 +++++-- .../node/extensionGalleryService.ts | 42 ++++++++++--------- .../node/extensionManagementService.ts | 2 +- .../node/extensionManagementUtil.ts | 16 ++++--- .../extensions/common/extensionsInput.ts | 11 +++-- .../electron-browser/extensionEditor.ts | 2 +- .../electron-browser/extensionsList.ts | 32 +++++--------- .../electron-browser/extensionsViewlet.ts | 16 +++---- 9 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index e3f53fd1bfd..01c7c66c9b4 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -94,8 +94,8 @@ class Main { console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); console.log(localize('installing', "Installing...")); - return this.extensionManagementService.install(extension).then(() => { - console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version)); + return this.extensionManagementService.install(extension.manifest).then(() => { + console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.manifest.version)); }); }); }); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index c9406437cb8..d6ecdb66efa 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -44,6 +44,16 @@ export interface IExtension extends IExtensionManifest { path?: string; } +export interface IGalleryExtension extends IGalleryMetadata { + manifest: IExtensionManifest; + // name: galleryExtension.extensionName, + // displayName: galleryExtension.displayName || galleryExtension.extensionName, + // publisher: galleryExtension.publisher.publisherName, + // version: versions[0].version, + // engines: { vscode: void 0 }, // TODO: ugly + // description: galleryExtension.shortDescription || '', +} + export const IExtensionManagementService = createDecorator('extensionManagementService'); export const IExtensionGalleryService = createDecorator('extensionGalleryService'); @@ -54,10 +64,10 @@ export interface IQueryOptions { } export interface IQueryResult { - firstPage: IExtension[]; + firstPage: IGalleryExtension[]; total: number; pageSize: number; - getPage(pageNumber: number): TPromise; + getPage(pageNumber: number): TPromise; } export interface IExtensionGalleryService { @@ -76,7 +86,7 @@ export interface IExtensionManagementService { onUninstallExtension: Event; onDidUninstallExtension: Event; - install(extension: IExtension): TPromise; + install(extension: IExtensionManifest): TPromise; install(zipPath: string): TPromise; uninstall(extension: IExtension): TPromise; getInstalled(includeDuplicateVersions?: boolean): TPromise; diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 881e81e4544..801036ef0f6 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { IExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -12,29 +12,29 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import pkg from 'vs/platform/package'; import product from 'vs/platform/product'; -export interface IGalleryExtensionFile { +interface IRawGalleryExtensionFile { assetType: string; } -export interface IGalleryExtensionVersion { +interface IRawGalleryExtensionVersion { version: string; lastUpdated: string; assetUri: string; - files: IGalleryExtensionFile[]; + files: IRawGalleryExtensionFile[]; } -export interface IGalleryExtension { +interface IRawGalleryExtension { extensionId: string; extensionName: string; displayName: string; shortDescription: string; publisher: { displayName: string, publisherId: string, publisherName: string; }; - versions: IGalleryExtensionVersion[]; + versions: IRawGalleryExtensionVersion[]; galleryApiUrl: string; - statistics: IGalleryExtensionStatistics[]; + statistics: IRawGalleryExtensionStatistics[]; } -export interface IGalleryExtensionStatistics { +interface IRawGalleryExtensionStatistics { statisticName: string; value: number; } @@ -152,7 +152,7 @@ class Query { } } -function getInstallCount(statistics: IGalleryExtensionStatistics[]): number { +function getInstallCount(statistics: IRawGalleryExtensionStatistics[]): number { if (!statistics) { return 0; } @@ -161,7 +161,7 @@ function getInstallCount(statistics: IGalleryExtensionStatistics[]): number { return result ? result.value : 0; } -function toExtension(galleryExtension: IGalleryExtension, extensionsGalleryUrl: string, downloadHeaders: any): IExtension { +function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUrl: string, downloadHeaders: any): IGalleryExtension { const versions = galleryExtension.versions.map(v => ({ version: v.version, date: v.lastUpdated, @@ -172,21 +172,23 @@ function toExtension(galleryExtension: IGalleryExtension, extensionsGalleryUrl: iconUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Icons.Default` })); - return { + const manifest = { name: galleryExtension.extensionName, displayName: galleryExtension.displayName || galleryExtension.extensionName, publisher: galleryExtension.publisher.publisherName, version: versions[0].version, engines: { vscode: void 0 }, // TODO: ugly description: galleryExtension.shortDescription || '', - galleryInformation: { - galleryApiUrl: extensionsGalleryUrl, - id: galleryExtension.extensionId, - publisherId: galleryExtension.publisher.publisherId, - publisherDisplayName: galleryExtension.publisher.displayName, - installCount: getInstallCount(galleryExtension.statistics), - versions - } + }; + + return { + galleryApiUrl: extensionsGalleryUrl, + id: galleryExtension.extensionId, + publisherId: galleryExtension.publisher.publisherId, + publisherDisplayName: galleryExtension.publisher.displayName, + installCount: getInstallCount(galleryExtension.statistics), + versions, + manifest }; } @@ -253,7 +255,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { }); } - private queryGallery(query: Query): TPromise<{ galleryExtensions: IGalleryExtension[], total: number; }> { + private queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> { const data = JSON.stringify(query.raw); return this.getRequestHeaders() diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 65bba93150d..b47e98a49c6 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -126,7 +126,7 @@ export class ExtensionManagementService implements IExtensionManagementService { // ]; } - install(extension: IExtension): TPromise; + install(extension: IExtensionManifest): TPromise; install(zipPath: string): TPromise; install(arg: any): TPromise { if (types.isString(arg)) { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 16e731698e5..7716759e12c 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IExtension, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IExtensionManifest, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TPromise } from 'vs/base/common/winjs.base'; import * as semver from 'semver'; @@ -13,7 +13,7 @@ export function getExtensionId(extension: IExtension): string { return `${ extension.publisher }.${ extension.name }`; } -export function extensionEquals(one: IExtension, other: IExtension): boolean { +export function extensionEquals(one: IExtensionManifest, other: IExtensionManifest): boolean { return one.publisher === other.publisher && one.name === other.name; } @@ -39,10 +39,14 @@ export function getOutdatedExtensions(extensionsService: IExtensionManagementSer return galleryService.query({ ids, pageSize: 1000 }).then(result => { const available = result.firstPage; - return available.filter(extension => { - const local = installed.filter(local => extensionEquals(local, extension))[0]; - return local && semver.lt(local.version, extension.version); - }); + return available.map(extension => { + const local = installed.filter(local => extensionEquals(local, extension.manifest))[0]; + if (local && semver.lt(local.version, extension.manifest.version)) { + return local; + } else { + return null; + } + }).filter(e => !!e); }); }); } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index d2c2d654e22..cfb5b811aba 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,15 +7,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { IExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { extensionEquals } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; +import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): IExtension { return this._extension; } + get extension(): IGalleryExtension { return this._extension; } - constructor(private _extension: IExtension) { + constructor(private _extension: IGalleryExtension) { super(); } @@ -24,7 +23,7 @@ export class ExtensionsInput extends EditorInput { } getName(): string { - return this.extension.displayName; + return this.extension.manifest.displayName; } matches(other: any): boolean { @@ -33,7 +32,7 @@ export class ExtensionsInput extends EditorInput { } const otherExtensionInput = other as ExtensionsInput; - return extensionEquals(this.extension, otherExtensionInput.extension); + return this.extension.id === otherExtensionInput.extension.id; } resolve(refresh?: boolean): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index e077fa20b38..7f58a2d3c32 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -62,7 +62,7 @@ export class ExtensionEditor extends BaseEditor { addClass(this.body, 'loading'); this.body.innerHTML = ''; - const [version] = input.extension.galleryInformation.versions; + const [version] = input.extension.versions; const headers = version.downloadHeaders; const promise = super.setInput(input, options) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 5337073f50a..7f3e59402cf 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export interface ITemplateData { - extension: IExtension; + extension: IGalleryExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,23 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export enum ExtensionState { - Uninstalled, - Installed, - Outdated -} - -export interface IExtensionEntry { - extension: IExtension; - state: ExtensionState; -} - -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -75,18 +64,17 @@ export class Renderer implements IPagedRenderer data.description.textContent = ''; } - renderElement(entry: IExtensionEntry, index: number, data: ITemplateData): void { - const extension = entry.extension; - const publisher = extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : extension.publisher; - const version = extension.galleryInformation.versions[0]; + renderElement(extension: IGalleryExtension, index: number, data: ITemplateData): void { + const publisher = extension ? extension.publisherDisplayName : extension.manifest.publisher; + const version = extension.versions[0]; data.extension = extension; removeClass(data.element, 'loading'); data.icon.src = version.iconUrl; - data.name.textContent = extension.displayName; - data.version.textContent = ` ${ extension.version }`; + data.name.textContent = extension.manifest.displayName; + data.version.textContent = ` ${ extension.manifest.version }`; data.author.textContent = ` ${ publisher }`; - data.description.textContent = extension.description; + data.description.textContent = extension.manifest.description; } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 2dafea78027..89a6852a492 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -13,12 +13,12 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { Viewlet } from 'vs/workbench/browser/viewlet'; import { append, emmet as $ } from 'vs/base/browser/dom'; -import { PagedModel, mapPager } from 'vs/base/common/paging'; +import { PagedModel } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionEntry, Delegate, Renderer, ExtensionState } from './extensionsList'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { Delegate, Renderer } from './extensionsList'; +import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -39,7 +39,7 @@ export class ExtensionsViewlet extends Viewlet { private root: HTMLElement; private searchBox: HTMLInputElement; private extensionsBox: HTMLElement; - private list: PagedList; + private list: PagedList; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -70,13 +70,13 @@ export class ExtensionsViewlet extends Viewlet { this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); this.list.onSelectionChange(e => { - const [entry] = e.elements; + const [extension] = e.elements; - if (!entry) { + if (!extension) { return; } - return this.editorService.openEditor(new ExtensionsInput(entry.extension)); + return this.editorService.openEditor(new ExtensionsInput(extension)); }, null, this.disposables); return TPromise.as(null); @@ -110,7 +110,7 @@ export class ExtensionsViewlet extends Viewlet { private doSearch(text: string = ''): TPromise { return this.galleryService.query({ text }) - .then(result => new PagedModel(mapPager(result, extension => ({ extension, state: ExtensionState.Installed })))) + .then(result => new PagedModel(result)) .then(model => this.list.model = model); } From 60798fdae03302fc6203e2009a49f4a3f5453779 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 18:54:57 +0200 Subject: [PATCH 044/126] remove galleryInformation --- src/vs/code/node/cliProcessMain.ts | 2 +- .../common/extensionManagement.ts | 3 +- .../common/extensionManagementIpc.ts | 4 +- .../node/extensionManagementService.ts | 48 +++++++++---------- .../node/extensionManagementUtil.ts | 20 ++++---- .../electron-browser/extensionsActions.ts | 14 +++--- 6 files changed, 44 insertions(+), 47 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 01c7c66c9b4..646e564e72f 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -94,7 +94,7 @@ class Main { console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); console.log(localize('installing', "Installing...")); - return this.extensionManagementService.install(extension.manifest).then(() => { + return this.extensionManagementService.install(extension).then(() => { console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.manifest.version)); }); }); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index d6ecdb66efa..d7e1c8df709 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -40,7 +40,6 @@ export interface IGalleryMetadata { } export interface IExtension extends IExtensionManifest { - galleryInformation?: IGalleryMetadata; path?: string; } @@ -86,7 +85,7 @@ export interface IExtensionManagementService { onUninstallExtension: Event; onDidUninstallExtension: Event; - install(extension: IExtensionManifest): TPromise; + install(extension: IGalleryExtension): TPromise; install(zipPath: string): TPromise; uninstall(extension: IExtension): TPromise; getInstalled(includeDuplicateVersions?: boolean): TPromise; diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 7863dddce0b..e64fa00a6f5 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, IExtension, DidInstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, IExtension, IGalleryExtension, DidInstallExtensionEvent } from './extensionManagement'; import Event from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -56,7 +56,7 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } - install(extension: IExtension): TPromise; + install(extension: IGalleryExtension): TPromise; install(zipPath: string): TPromise; install(arg: any): TPromise { return this.channel.call('install', arg); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index b47e98a49c6..64a8412a066 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, IExtension, IExtensionManifest, IGalleryMetadata, IGalleryVersion } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionManifest, IGalleryVersion } from 'vs/platform/extensionManagement/common/extensionManagement'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -60,7 +60,7 @@ function validate(zipPath: string, extension?: IExtension, version = extension & }); } -function createExtension(manifest: IExtensionManifest, galleryInformation?: IGalleryMetadata, path?: string): IExtension { +function createExtension(manifest: IExtensionManifest, path?: string): IExtension { const extension: IExtension = { name: manifest.name, displayName: manifest.displayName || manifest.name, @@ -70,9 +70,9 @@ function createExtension(manifest: IExtensionManifest, galleryInformation?: IGal description: manifest.description || '' }; - if (galleryInformation) { - extension.galleryInformation = galleryInformation; - } + // if (galleryInformation) { + // extension.galleryInformation = galleryInformation; + // } if (path) { extension.path = path; @@ -126,7 +126,7 @@ export class ExtensionManagementService implements IExtensionManagementService { // ]; } - install(extension: IExtensionManifest): TPromise; + install(extension: IGalleryExtension): TPromise; install(zipPath: string): TPromise; install(arg: any): TPromise { if (types.isString(arg)) { @@ -143,39 +143,35 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private installFromGallery(extension: IExtension): TPromise { - const id = getExtensionId(extension); - const galleryInformation = extension.galleryInformation; - - if (!galleryInformation) { - return TPromise.wrapError(new Error(nls.localize('missingGalleryInformation', "Gallery information is missing"))); - } + private installFromGallery(extension: IGalleryExtension): TPromise { + const id = getExtensionId(extension.manifest); this._onInstallExtension.fire(id); - return this.getLastValidExtensionVersion(extension, extension.galleryInformation.versions).then(versionInfo => { + return this.getLastValidExtensionVersion(extension).then(versionInfo => { const version = versionInfo.version; const url = versionInfo.downloadUrl; const headers = versionInfo.downloadHeaders; - const zipPath = path.join(tmpdir(), galleryInformation.id); - const extensionPath = path.join(this.extensionsPath, getExtensionId(extension, version)); - const manifestPath = path.join(extensionPath, 'package.json'); + const zipPath = path.join(tmpdir(), extension.id); + const extensionPath = path.join(this.extensionsPath, getExtensionId(extension.manifest, version)); return this.request(url) .then(opts => assign(opts, { headers })) .then(opts => download(zipPath, opts)) - .then(() => validate(zipPath, extension, version)) - .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest)) - .then(manifest => assign({ __metadata: galleryInformation }, manifest)) - .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => validate(zipPath, extension.manifest, version)) + .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true })) .then(() => this._onDidInstallExtension.fire({ id })) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); } - private getLastValidExtensionVersion(extension: IExtension, versions: IGalleryVersion[]): TPromise { + private getLastValidExtensionVersion(extension: IGalleryExtension): TPromise { + return this._getLastValidExtensionVersion(extension, extension.versions); + } + + private _getLastValidExtensionVersion(extension: IGalleryExtension, versions: IGalleryVersion[]): TPromise { if (!versions.length) { - return TPromise.wrapError(new Error(nls.localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.displayName))); + return TPromise.wrapError(new Error(nls.localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.manifest.displayName))); } const version = versions[0]; @@ -189,7 +185,7 @@ export class ExtensionManagementService implements IExtensionManagementService { }; if (!isValidExtensionVersion(pkg.version, desc, [])) { - return this.getLastValidExtensionVersion(extension, versions.slice(1)); + return this._getLastValidExtensionVersion(extension, versions.slice(1)); } return version; @@ -203,7 +199,7 @@ export class ExtensionManagementService implements IExtensionManagementService { this._onInstallExtension.fire(id); return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) - .then(() => createExtension(manifest, ( manifest).__metadata, extensionPath)) + .then(() => createExtension(manifest, extensionPath)) .then(extension => this._onDidInstallExtension.fire({ id })) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); @@ -248,7 +244,7 @@ export class ExtensionManagementService implements IExtensionManagementService { return limiter.queue( () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(manifest => createExtension(manifest, ( manifest).__metadata, extensionPath)) + .then(manifest => createExtension(manifest, extensionPath)) .then(null, () => null) ); }))) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 7716759e12c..8d2fd813572 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -17,15 +17,17 @@ export function extensionEquals(one: IExtensionManifest, other: IExtensionManife return one.publisher === other.publisher && one.name === other.name; } -export function getTelemetryData(extension: IExtension): any { - return { - id: getExtensionId(extension), - name: extension.name, - galleryId: extension.galleryInformation ? extension.galleryInformation.id : null, - publisherId: extension.galleryInformation ? extension.galleryInformation.publisherId : null, - publisherName: extension.publisher, - publisherDisplayName: extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : null - }; +export function getTelemetryData(extension: any): any { + return {}; + // TODO + // return { + // id: getExtensionId(extension), + // name: extension.name, + // galleryId: extension.galleryInformation ? extension.galleryInformation.id : null, + // publisherId: extension.galleryInformation ? extension.galleryInformation.publisherId : null, + // publisherName: extension.publisher, + // publisherDisplayName: extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : null + // }; } export function getOutdatedExtensions(extensionsService: IExtensionManagementService, galleryService: IExtensionGalleryService): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index a7e0780b4ea..0b3c6c1985b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IMessageService } from 'vs/platform/message/common/message'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; -import { IExtensionManagementService, IExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; @@ -123,11 +123,11 @@ export class InstallAction extends Action { super('extensions.install', label, 'octicon octicon-cloud-download', true); } - public run(extension: IExtension): TPromise { + public run(extension: IGalleryExtension): TPromise { this.enabled = false; return this.extensionManagementService.getInstalled() - .then(installed => installed.some(e => extensionEquals(e, extension))) + .then(installed => installed.some(e => extensionEquals(e, extension.manifest))) .then(isUpdate => { return this.extensionManagementService .install(extension) @@ -137,10 +137,10 @@ export class InstallAction extends Action { }); } - private onSuccess(extension: IExtension, isUpdate: boolean) { + private onSuccess(extension: IGalleryExtension, isUpdate: boolean) { this.reportTelemetry(extension, isUpdate, true); this.messageService.show(Severity.Info, { - message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName), + message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.manifest.displayName), actions: [ CloseAction, this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now")) @@ -148,12 +148,12 @@ export class InstallAction extends Action { }); } - private onError(err: Error, extension: IExtension, isUpdate: boolean) { + private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) { this.reportTelemetry(extension, isUpdate, false); this.messageService.show(Severity.Error, err); } - private reportTelemetry(extension: IExtension, isUpdate: boolean, success: boolean) { + private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) { const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install'; const data = assign(getTelemetryData(extension), { success }); From 4c8410c1a13bcd86e0c3e5261be39e7b0defea94 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 19:08:42 +0200 Subject: [PATCH 045/126] extension.manifest --- src/vs/code/node/cliProcessMain.ts | 13 +++--- .../common/extensionManagement.ts | 3 +- .../node/extensionManagementService.ts | 44 +++++++++---------- .../node/extensionManagementUtil.ts | 10 ++--- .../electron-browser/extensionsActions.ts | 26 ++++++----- 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 646e564e72f..f3cb2d252de 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -17,8 +17,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IEventService } from 'vs/platform/event/common/event'; import { EventService } from 'vs/platform/event/common/eventService'; -import { IExtensionManagementService, IExtensionGalleryService, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getExtensionId } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; +import { IExtensionManagementService, IExtensionGalleryService, IQueryResult, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { ITelemetryService, combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -34,6 +33,10 @@ const notFound = id => localize('notFound', "Extension '{0}' not found.", id); const notInstalled = id => localize('notInstalled', "Extension '{0}' is not installed.", id); const useId = localize('useId', "Make sure you use the full extension ID, eg: {0}", 'ms-vscode.csharp'); +function getId(manifest: IExtensionManifest): string { + return `${ manifest.publisher }.${ manifest.name }`; +} + class Main { constructor( @@ -59,14 +62,14 @@ class Main { private listExtensions(): TPromise { return this.extensionManagementService.getInstalled().then(extensions => { - extensions.forEach(e => console.log(getExtensionId(e))); + extensions.forEach(e => console.log(getId(e.manifest))); }); } private installExtension(ids: string[]): TPromise { return sequence(ids.map(id => () => { return this.extensionManagementService.getInstalled().then(installed => { - const isInstalled = installed.some(e => getExtensionId(e) === id); + const isInstalled = installed.some(e => getId(e.manifest) === id); if (isInstalled) { console.log(localize('alreadyInstalled', "Extension '{0}' is already installed.", id)); @@ -105,7 +108,7 @@ class Main { private uninstallExtension(ids: string[]): TPromise { return sequence(ids.map(id => () => { return this.extensionManagementService.getInstalled().then(installed => { - const [extension] = installed.filter(e => getExtensionId(e) === id); + const [extension] = installed.filter(e => getId(e.manifest) === id); if (!extension) { return TPromise.wrapError(`${ notInstalled(id) }\n${ useId }`); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index d7e1c8df709..fc6717618eb 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -39,7 +39,8 @@ export interface IGalleryMetadata { versions: IGalleryVersion[]; } -export interface IExtension extends IExtensionManifest { +export interface IExtension { + manifest: IExtensionManifest; path?: string; } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 64a8412a066..c3cca95c29b 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -38,7 +38,7 @@ function parseManifest(raw: string): TPromise { }); } -function validate(zipPath: string, extension?: IExtension, version = extension && extension.version): TPromise { +function validate(zipPath: string, extension?: IExtensionManifest, version = extension && extension.version): TPromise { return buffer(zipPath, 'extension/package.json') .then(buffer => parseManifest(buffer.toString('utf8'))) .then(manifest => { @@ -61,14 +61,7 @@ function validate(zipPath: string, extension?: IExtension, version = extension & } function createExtension(manifest: IExtensionManifest, path?: string): IExtension { - const extension: IExtension = { - name: manifest.name, - displayName: manifest.displayName || manifest.name, - publisher: manifest.publisher, - version: manifest.version, - engines: { vscode: manifest.engines.vscode }, - description: manifest.description || '' - }; + const extension: IExtension = { manifest }; // if (galleryInformation) { // extension.galleryInformation = galleryInformation; @@ -133,10 +126,12 @@ export class ExtensionManagementService implements IExtensionManagementService { return this.installFromZip(arg); } - const extension = arg as IExtension; + const extension = arg as IGalleryExtension; + const { manifest } = extension; + return this.isObsolete(extension).then(obsolete => { if (obsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.name))); + return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.name))); } return this.installFromGallery(arg); @@ -206,8 +201,9 @@ export class ExtensionManagementService implements IExtensionManagementService { } uninstall(extension: IExtension): TPromise { - const extensionPath = extension.path || path.join(this.extensionsPath, getExtensionId(extension)); - const id = getExtensionId(extension); + const { manifest } = extension; + const id = getExtensionId(manifest); + const extensionPath = extension.path || path.join(this.extensionsPath, id); return pfs.exists(extensionPath) .then(exists => exists ? null : Promise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) @@ -226,8 +222,8 @@ export class ExtensionManagementService implements IExtensionManagementService { } return all.then(extensions => { - const byId = values(groupBy(extensions, p => `${ p.publisher }.${ p.name }`)); - return byId.map(p => p.sort((a, b) => semver.rcompare(a.version, b.version))[0]); + const byId = values(groupBy(extensions, p => `${ p.manifest.publisher }.${ p.manifest.name }`)); + return byId.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version))[0]); }); } @@ -254,7 +250,7 @@ export class ExtensionManagementService implements IExtensionManagementService { removeDeprecatedExtensions(): TPromise { const outdated = this.getOutdatedExtensions() - .then(extensions => extensions.map(e => getExtensionId(e))); + .then(extensions => extensions.map(({ manifest }) => getExtensionId(manifest))); const obsolete = this.getObsoleteExtensions() .then(obsolete => Object.keys(obsolete)); @@ -271,26 +267,26 @@ export class ExtensionManagementService implements IExtensionManagementService { private getOutdatedExtensions(): TPromise { return this.getAllInstalled().then(plugins => { - const byId = values(groupBy(plugins, p => `${ p.publisher }.${ p.name }`)); - const extensions = flatten(byId.map(p => p.sort((a, b) => semver.rcompare(a.version, b.version)).slice(1))); + const byId = values(groupBy(plugins, p => `${ p.manifest.publisher }.${ p.manifest.name }`)); + const extensions = flatten(byId.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1))); return extensions .filter(e => !!e.path); }); } - private isObsolete(extension: IExtension): TPromise { - const id = getExtensionId(extension); + private isObsolete({ manifest }: IExtension): TPromise { + const id = getExtensionId(manifest); return this.withObsoleteExtensions(obsolete => !!obsolete[id]); } - private setObsolete(extension: IExtension): TPromise { - const id = getExtensionId(extension); + private setObsolete({ manifest }: IExtension): TPromise { + const id = getExtensionId(manifest); return this.withObsoleteExtensions(obsolete => assign(obsolete, { [id]: true })); } - private unsetObsolete(extension: IExtension): TPromise { - const id = getExtensionId(extension); + private unsetObsolete({ manifest }: IExtension): TPromise { + const id = getExtensionId(manifest); return this.withObsoleteExtensions(obsolete => delete obsolete[id]); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 8d2fd813572..5ec8ff29733 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -9,10 +9,6 @@ import { IExtension, IExtensionManifest, IExtensionManagementService, IExtension import { TPromise } from 'vs/base/common/winjs.base'; import * as semver from 'semver'; -export function getExtensionId(extension: IExtension): string { - return `${ extension.publisher }.${ extension.name }`; -} - export function extensionEquals(one: IExtensionManifest, other: IExtensionManifest): boolean { return one.publisher === other.publisher && one.name === other.name; } @@ -36,14 +32,14 @@ export function getOutdatedExtensions(extensionsService: IExtensionManagementSer } return extensionsService.getInstalled().then(installed => { - const ids = installed.map(getExtensionId); + const ids = installed.map(({ manifest }) => `${ manifest.publisher }.${ manifest.name }`); return galleryService.query({ ids, pageSize: 1000 }).then(result => { const available = result.firstPage; return available.map(extension => { - const local = installed.filter(local => extensionEquals(local, extension.manifest))[0]; - if (local && semver.lt(local.version, extension.manifest.version)) { + const local = installed.filter(local => extensionEquals(local.manifest, extension.manifest))[0]; + if (local && semver.lt(local.manifest.version, extension.manifest.version)) { return local; } else { return null; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 0b3c6c1985b..1614289b351 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -32,7 +32,7 @@ export class ListExtensionsAction extends Action { super(id, label, null, true); } - public run(): Promise { + run(): Promise { return this.quickOpenService.show('ext '); } @@ -55,7 +55,7 @@ export class InstallExtensionAction extends Action { super(id, label, null, true); } - public run(): Promise { + run(): Promise { return this.quickOpenService.show('ext install '); } @@ -78,7 +78,7 @@ export class ListOutdatedExtensionsAction extends Action { super(id, label, null, true); } - public run(): Promise { + run(): Promise { return this.quickOpenService.show('ext update '); } @@ -101,7 +101,7 @@ export class ListSuggestedExtensionsAction extends Action { super(id, label, null, true); } - public run(): Promise { + run(): Promise { return this.quickOpenService.show('ext recommend '); } @@ -123,11 +123,11 @@ export class InstallAction extends Action { super('extensions.install', label, 'octicon octicon-cloud-download', true); } - public run(extension: IGalleryExtension): TPromise { + run(extension: IGalleryExtension): TPromise { this.enabled = false; return this.extensionManagementService.getInstalled() - .then(installed => installed.some(e => extensionEquals(e, extension.manifest))) + .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension.manifest))) .then(isUpdate => { return this.extensionManagementService .install(extension) @@ -173,18 +173,20 @@ export class UninstallAction extends Action { super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true); } - public run(extension: IExtension): TPromise { - if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", extension.displayName))) { + run(extension: IExtension): TPromise { + const name = extension.manifest.displayName || extension.manifest.name; + + if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) { return TPromise.as(null); } this.enabled = false; return this.extensionManagementService.getInstalled().then(localExtensions => { - const [local] = localExtensions.filter(local => extensionEquals(local, extension)); + const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest)); if (!local) { - return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", extension.displayName)); + return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name)); } return this.extensionManagementService.uninstall(local) @@ -195,9 +197,11 @@ export class UninstallAction extends Action { } private onSuccess(extension: IExtension) { + const name = extension.manifest.displayName || extension.manifest.name; this.reportTelemetry(extension, true); + this.messageService.show(Severity.Info, { - message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", extension.displayName), + message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", name), actions: [ CloseAction, this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow2', "Restart Now")) From a1619bc726ba31674e20d115ccd5137ca29ebd6d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 19:18:28 +0200 Subject: [PATCH 046/126] extension: path not optional --- .../common/extensionManagement.ts | 2 +- .../node/extensionManagementService.ts | 34 +++++-------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index fc6717618eb..4db09daf5ab 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -41,7 +41,7 @@ export interface IGalleryMetadata { export interface IExtension { manifest: IExtensionManifest; - path?: string; + path: string; } export interface IGalleryExtension extends IGalleryMetadata { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index c3cca95c29b..4a8b2b0f867 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -60,20 +60,6 @@ function validate(zipPath: string, extension?: IExtensionManifest, version = ext }); } -function createExtension(manifest: IExtensionManifest, path?: string): IExtension { - const extension: IExtension = { manifest }; - - // if (galleryInformation) { - // extension.galleryInformation = galleryInformation; - // } - - if (path) { - extension.path = path; - } - - return extension; -} - function getExtensionId(extension: IExtensionManifest, version = extension.version): string { return `${ extension.publisher }.${ extension.name }-${ version }`; } @@ -128,8 +114,9 @@ export class ExtensionManagementService implements IExtensionManagementService { const extension = arg as IGalleryExtension; const { manifest } = extension; + const id = getExtensionId(manifest); - return this.isObsolete(extension).then(obsolete => { + return this.isObsolete(id).then(obsolete => { if (obsolete) { return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.name))); } @@ -194,7 +181,7 @@ export class ExtensionManagementService implements IExtensionManagementService { this._onInstallExtension.fire(id); return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) - .then(() => createExtension(manifest, extensionPath)) + .then(() => ({ manifest, path: extensionPath })) .then(extension => this._onDidInstallExtension.fire({ id })) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); @@ -208,9 +195,9 @@ export class ExtensionManagementService implements IExtensionManagementService { return pfs.exists(extensionPath) .then(exists => exists ? null : Promise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) .then(() => this._onUninstallExtension.fire(id)) - .then(() => this.setObsolete(extension)) + .then(() => this.setObsolete(id)) .then(() => pfs.rimraf(extensionPath)) - .then(() => this.unsetObsolete(extension)) + .then(() => this.unsetObsolete(id)) .then(() => this._onDidUninstallExtension.fire(id)); } @@ -240,7 +227,7 @@ export class ExtensionManagementService implements IExtensionManagementService { return limiter.queue( () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(manifest => createExtension(manifest, extensionPath)) + .then(manifest => ({ manifest, path: extensionPath })) .then(null, () => null) ); }))) @@ -275,18 +262,15 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private isObsolete({ manifest }: IExtension): TPromise { - const id = getExtensionId(manifest); + private isObsolete(id: string): TPromise { return this.withObsoleteExtensions(obsolete => !!obsolete[id]); } - private setObsolete({ manifest }: IExtension): TPromise { - const id = getExtensionId(manifest); + private setObsolete(id: string): TPromise { return this.withObsoleteExtensions(obsolete => assign(obsolete, { [id]: true })); } - private unsetObsolete({ manifest }: IExtension): TPromise { - const id = getExtensionId(manifest); + private unsetObsolete(id: string): TPromise { return this.withObsoleteExtensions(obsolete => delete obsolete[id]); } From 42f6b37042a9be3450f7fa7ab753e1eab5251c9a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jun 2016 19:24:01 +0200 Subject: [PATCH 047/126] :lipstick: --- .../extensionManagement/common/extensionManagement.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 4db09daf5ab..57c9813b2cc 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -46,12 +46,6 @@ export interface IExtension { export interface IGalleryExtension extends IGalleryMetadata { manifest: IExtensionManifest; - // name: galleryExtension.extensionName, - // displayName: galleryExtension.displayName || galleryExtension.extensionName, - // publisher: galleryExtension.publisher.publisherName, - // version: versions[0].version, - // engines: { vscode: void 0 }, // TODO: ugly - // description: galleryExtension.shortDescription || '', } export const IExtensionManagementService = createDecorator('extensionManagementService'); From f80b677a51c47744aedf912e4445c958ec11ffd4 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 09:12:00 +0200 Subject: [PATCH 048/126] drop galleryApiUrl --- .../extensionManagement/common/extensionManagement.ts | 9 ++++----- .../extensionManagement/node/extensionGalleryService.ts | 2 -- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 57c9813b2cc..92508dbd627 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -31,7 +31,6 @@ export interface IGalleryVersion { } export interface IGalleryMetadata { - galleryApiUrl: string; id: string; publisherId: string; publisherDisplayName: string; @@ -39,15 +38,15 @@ export interface IGalleryMetadata { versions: IGalleryVersion[]; } +export interface IGalleryExtension extends IGalleryMetadata { + manifest: IExtensionManifest; +} + export interface IExtension { manifest: IExtensionManifest; path: string; } -export interface IGalleryExtension extends IGalleryMetadata { - manifest: IExtensionManifest; -} - export const IExtensionManagementService = createDecorator('extensionManagementService'); export const IExtensionGalleryService = createDecorator('extensionGalleryService'); diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 801036ef0f6..b2432f62573 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -30,7 +30,6 @@ interface IRawGalleryExtension { shortDescription: string; publisher: { displayName: string, publisherId: string, publisherName: string; }; versions: IRawGalleryExtensionVersion[]; - galleryApiUrl: string; statistics: IRawGalleryExtensionStatistics[]; } @@ -182,7 +181,6 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr }; return { - galleryApiUrl: extensionsGalleryUrl, id: galleryExtension.extensionId, publisherId: galleryExtension.publisher.publisherId, publisherDisplayName: galleryExtension.publisher.displayName, From bccc0dcdec5fe8ef75ebb418f14fb227485f898f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 09:32:19 +0200 Subject: [PATCH 049/126] drop extension.path --- .../common/extensionManagement.ts | 9 ++--- .../node/extensionManagementService.ts | 34 ++++++++----------- .../electron-browser/extensionsViewlet.ts | 7 +++- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 92508dbd627..40b000f17e6 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -30,21 +30,18 @@ export interface IGalleryVersion { downloadHeaders: { [key: string]: string; }; } -export interface IGalleryMetadata { +export interface IGalleryExtension { id: string; + manifest: IExtensionManifest; publisherId: string; publisherDisplayName: string; installCount: number; versions: IGalleryVersion[]; } -export interface IGalleryExtension extends IGalleryMetadata { - manifest: IExtensionManifest; -} - export interface IExtension { + id: string; manifest: IExtensionManifest; - path: string; } export const IExtensionManagementService = createDecorator('extensionManagementService'); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 4a8b2b0f867..4809a7f0f43 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -177,20 +177,18 @@ export class ExtensionManagementService implements IExtensionManagementService { private installFromZip(zipPath: string): TPromise { return validate(zipPath).then(manifest => { const id = getExtensionId(manifest); - const extensionPath = path.join(this.extensionsPath, getExtensionId(manifest)); + const extensionPath = path.join(this.extensionsPath, id); this._onInstallExtension.fire(id); return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) - .then(() => ({ manifest, path: extensionPath })) - .then(extension => this._onDidInstallExtension.fire({ id })) + .then(() => this._onDidInstallExtension.fire({ id })) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); }); } uninstall(extension: IExtension): TPromise { - const { manifest } = extension; - const id = getExtensionId(manifest); - const extensionPath = extension.path || path.join(this.extensionsPath, id); + const id = extension.id; + const extensionPath = path.join(this.extensionsPath, id); return pfs.exists(extensionPath) .then(exists => exists ? null : Promise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) @@ -220,14 +218,14 @@ export class ExtensionManagementService implements IExtensionManagementService { return this.getObsoleteExtensions() .then(obsolete => { return pfs.readdir(this.extensionsPath) - .then(extensions => extensions.filter(e => !obsolete[e])) - .then(extensions => Promise.join(extensions.map(e => { - const extensionPath = path.join(this.extensionsPath, e); + .then(extensions => extensions.filter(id => !obsolete[id])) + .then(extensionIds => Promise.join(extensionIds.map(id => { + const extensionPath = path.join(this.extensionsPath, id); return limiter.queue( () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(manifest => ({ manifest, path: extensionPath })) + .then(manifest => ({ id, manifest })) .then(null, () => null) ); }))) @@ -236,8 +234,8 @@ export class ExtensionManagementService implements IExtensionManagementService { } removeDeprecatedExtensions(): TPromise { - const outdated = this.getOutdatedExtensions() - .then(extensions => extensions.map(({ manifest }) => getExtensionId(manifest))); + const outdated = this.getOutdatedExtensionIds() + .then(extensions => extensions.map(e => getExtensionId(e.manifest))); const obsolete = this.getObsoleteExtensions() .then(obsolete => Object.keys(obsolete)); @@ -252,14 +250,10 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private getOutdatedExtensions(): TPromise { - return this.getAllInstalled().then(plugins => { - const byId = values(groupBy(plugins, p => `${ p.manifest.publisher }.${ p.manifest.name }`)); - const extensions = flatten(byId.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1))); - - return extensions - .filter(e => !!e.path); - }); + private getOutdatedExtensionIds(): TPromise { + return this.getAllInstalled() + .then(extensions => values(groupBy(extensions, p => `${ p.manifest.publisher }.${ p.manifest.name }`))) + .then(versions => flatten(versions.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1)))); } private isObsolete(id: string): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 89a6852a492..c939bd17e45 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -18,7 +18,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Delegate, Renderer } from './extensionsList'; -import { IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -44,6 +44,7 @@ export class ExtensionsViewlet extends Viewlet { constructor( @ITelemetryService telemetryService: ITelemetryService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, + @IExtensionManagementService private extensionService: IExtensionManagementService, @IProgressService private progressService: IProgressService, @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService @@ -109,6 +110,10 @@ export class ExtensionsViewlet extends Viewlet { } private doSearch(text: string = ''): TPromise { + this.extensionService.getInstalled().then(r => { + console.log(r); + }); + return this.galleryService.query({ text }) .then(result => new PagedModel(result)) .then(model => this.list.model = model); From ec45ebf0f16fd4ba1eb14d8397e8e939001f60fb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 09:35:37 +0200 Subject: [PATCH 050/126] move gallery metadata to own field --- .../common/extensionManagement.ts | 10 +++++++--- .../node/extensionGalleryService.ts | 12 +++++++----- .../node/extensionManagementService.ts | 2 +- .../extensions/electron-browser/extensionEditor.ts | 2 +- .../extensions/electron-browser/extensionsList.ts | 4 ++-- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 40b000f17e6..b9a7515f0b5 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -30,15 +30,19 @@ export interface IGalleryVersion { downloadHeaders: { [key: string]: string; }; } -export interface IGalleryExtension { - id: string; - manifest: IExtensionManifest; +export interface IGalleryMetadata { publisherId: string; publisherDisplayName: string; installCount: number; versions: IGalleryVersion[]; } +export interface IGalleryExtension { + id: string; + manifest: IExtensionManifest; + metadata: IGalleryMetadata; +} + export interface IExtension { id: string; manifest: IExtensionManifest; diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index b2432f62573..c8b37d59125 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -182,11 +182,13 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr return { id: galleryExtension.extensionId, - publisherId: galleryExtension.publisher.publisherId, - publisherDisplayName: galleryExtension.publisher.displayName, - installCount: getInstallCount(galleryExtension.statistics), - versions, - manifest + manifest, + metadata: { + publisherId: galleryExtension.publisher.publisherId, + publisherDisplayName: galleryExtension.publisher.displayName, + installCount: getInstallCount(galleryExtension.statistics), + versions + } }; } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 4809a7f0f43..9f2201acef9 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -148,7 +148,7 @@ export class ExtensionManagementService implements IExtensionManagementService { } private getLastValidExtensionVersion(extension: IGalleryExtension): TPromise { - return this._getLastValidExtensionVersion(extension, extension.versions); + return this._getLastValidExtensionVersion(extension, extension.metadata.versions); } private _getLastValidExtensionVersion(extension: IGalleryExtension, versions: IGalleryVersion[]): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 7f58a2d3c32..34f15382fe6 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -62,7 +62,7 @@ export class ExtensionEditor extends BaseEditor { addClass(this.body, 'loading'); this.body.innerHTML = ''; - const [version] = input.extension.versions; + const [version] = input.extension.metadata.versions; const headers = version.downloadHeaders; const promise = super.setInput(input, options) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 7f3e59402cf..2a71a65cead 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -65,8 +65,8 @@ export class Renderer implements IPagedRenderer Date: Fri, 17 Jun 2016 09:52:27 +0200 Subject: [PATCH 051/126] add metadata to local extensions --- .../common/extensionManagement.ts | 1 + .../node/extensionManagementService.ts | 45 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index b9a7515f0b5..79f5ed4ea16 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -46,6 +46,7 @@ export interface IGalleryExtension { export interface IExtension { id: string; manifest: IExtensionManifest; + metadata: IGalleryMetadata; } export const IExtensionManagementService = createDecorator('extensionManagementService'); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 9f2201acef9..eaa9f02d64e 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionManifest, IGalleryVersion } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -28,10 +28,13 @@ import { groupBy, values } from 'vs/base/common/collections'; import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; import pkg from 'vs/platform/package'; -function parseManifest(raw: string): TPromise { +function parseManifest(raw: string): TPromise<{ manifest: IExtensionManifest; metadata: IGalleryMetadata; }> { return new Promise((c, e) => { try { - c(JSON.parse(raw)); + const manifest = JSON.parse(raw); + const metadata = manifest.__metadata || null; + delete manifest.__metadata; + c({ manifest, metadata }); } catch (err) { e(new Error(nls.localize('invalidManifest', "Extension invalid: package.json is not a JSON file."))); } @@ -41,7 +44,7 @@ function parseManifest(raw: string): TPromise { function validate(zipPath: string, extension?: IExtensionManifest, version = extension && extension.version): TPromise { return buffer(zipPath, 'extension/package.json') .then(buffer => parseManifest(buffer.toString('utf8'))) - .then(manifest => { + .then(({ manifest }) => { if (extension) { if (extension.name !== manifest.name) { return Promise.wrapError(Error(nls.localize('invalidName', "Extension invalid: manifest name mismatch."))); @@ -126,24 +129,18 @@ export class ExtensionManagementService implements IExtensionManagementService { } private installFromGallery(extension: IGalleryExtension): TPromise { - const id = getExtensionId(extension.manifest); - - this._onInstallExtension.fire(id); - return this.getLastValidExtensionVersion(extension).then(versionInfo => { const version = versionInfo.version; const url = versionInfo.downloadUrl; const headers = versionInfo.downloadHeaders; const zipPath = path.join(tmpdir(), extension.id); - const extensionPath = path.join(this.extensionsPath, getExtensionId(extension.manifest, version)); + const id = getExtensionId(extension.manifest, version); return this.request(url) .then(opts => assign(opts, { headers })) .then(opts => download(zipPath, opts)) .then(() => validate(zipPath, extension.manifest, version)) - .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true })) - .then(() => this._onDidInstallExtension.fire({ id })) - .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); + .then(() => this.installValidExtension(zipPath, id, extension.metadata)); }); } @@ -175,15 +172,21 @@ export class ExtensionManagementService implements IExtensionManagementService { } private installFromZip(zipPath: string): TPromise { - return validate(zipPath).then(manifest => { - const id = getExtensionId(manifest); - const extensionPath = path.join(this.extensionsPath, id); - this._onInstallExtension.fire(id); + return validate(zipPath).then(manifest => this.installValidExtension(zipPath, getExtensionId(manifest))); + } - return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) - .then(() => this._onDidInstallExtension.fire({ id })) - .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); - }); + private installValidExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { + const extensionPath = path.join(this.extensionsPath, id); + const manifestPath = path.join(extensionPath, 'package.json'); + this._onInstallExtension.fire(id); + + return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) + .then(() => pfs.readFile(manifestPath, 'utf8')) + .then(raw => parseManifest(raw)) + .then(({ manifest }) => assign(manifest, { __metadata: metadata })) + .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => this._onDidInstallExtension.fire({ id })) + .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); } uninstall(extension: IExtension): TPromise { @@ -225,7 +228,7 @@ export class ExtensionManagementService implements IExtensionManagementService { return limiter.queue( () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(manifest => ({ id, manifest })) + .then(({ manifest, metadata }) => ({ id, manifest, metadata })) .then(null, () => null) ); }))) From 68627ea1ec233c3c4e4358130c95aaf88cd1ee6b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 10:14:31 +0200 Subject: [PATCH 052/126] add path --- .../platform/extensionManagement/common/extensionManagement.ts | 1 + .../extensionManagement/node/extensionManagementService.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 79f5ed4ea16..1f3a6181449 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -47,6 +47,7 @@ export interface IExtension { id: string; manifest: IExtensionManifest; metadata: IGalleryMetadata; + path: string; } export const IExtensionManagementService = createDecorator('extensionManagementService'); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index eaa9f02d64e..919fdbdb390 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -228,7 +228,7 @@ export class ExtensionManagementService implements IExtensionManagementService { return limiter.queue( () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(({ manifest, metadata }) => ({ id, manifest, metadata })) + .then(({ manifest, metadata }) => ({ id, manifest, metadata, path: extensionPath })) .then(null, () => null) ); }))) From c590dbccb9a1251de20590a874f5edb9d96fda94 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 10:44:18 +0200 Subject: [PATCH 053/126] render default icon --- .../common/extensionManagement.ts | 2 ++ .../node/extensionGalleryService.ts | 4 +-- .../extensions/common/extensionsInput.ts | 6 ++-- .../electron-browser/extensionsList.ts | 31 +++++++++++++----- .../electron-browser/extensionsViewlet.ts | 22 ++++++------- .../electron-browser/media/defaultIcon.png | Bin 0 -> 1686 bytes 6 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/defaultIcon.png diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 1f3a6181449..33532c32e30 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -18,6 +18,7 @@ export interface IExtensionManifest { displayName?: string; description?: string; main?: string; + icon?: string; } export interface IGalleryVersion { @@ -41,6 +42,7 @@ export interface IGalleryExtension { id: string; manifest: IExtensionManifest; metadata: IGalleryMetadata; + path?: string; } export interface IExtension { diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index c8b37d59125..214d6ffe840 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionManifest, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -171,7 +171,7 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr iconUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Icons.Default` })); - const manifest = { + const manifest: IExtensionManifest = { name: galleryExtension.extensionName, displayName: galleryExtension.displayName || galleryExtension.extensionName, publisher: galleryExtension.publisher.publisherName, diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index cfb5b811aba..474132b1d10 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,14 +7,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): IGalleryExtension { return this._extension; } + get extension(): IExtension | IGalleryExtension { return this._extension; } - constructor(private _extension: IGalleryExtension) { + constructor(private _extension: IExtension | IGalleryExtension) { super(); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 2a71a65cead..a7526bdc2e8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export interface ITemplateData { - extension: IGalleryExtension; + extension: IExtension | IGalleryExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,12 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -64,14 +64,27 @@ export class Renderer implements IPagedRenderer(firstPage: T[]) { + return new PagedModel({ + firstPage, + total: firstPage.length, + pageSize: firstPage.length, + getPage: null + }); +} export class ExtensionsViewlet extends Viewlet { @@ -101,7 +103,7 @@ export class ExtensionsViewlet extends Viewlet { } private triggerSearch(text: string = '', delay = 500): void { - this.list.model = EmptyModel; + this.list.model = singlePageModel([]); const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); @@ -110,10 +112,8 @@ export class ExtensionsViewlet extends Viewlet { } private doSearch(text: string = ''): TPromise { - this.extensionService.getInstalled().then(r => { - console.log(r); - }); - + // return this.extensionService.getInstalled() + // .then(result => singlePageModel(result)) return this.galleryService.query({ text }) .then(result => new PagedModel(result)) .then(model => this.list.model = model); diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/defaultIcon.png b/src/vs/workbench/parts/extensions/electron-browser/media/defaultIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2f36a94347418ca5485406b38fc515a2f6c947e5 GIT binary patch literal 1686 zcmV;H25I?;P)YYKv;q9U~mV_3cwY}4#X7qXPq8`-2N9=&SnjIM?aT zfkwELV=o=-XUpiHk97@!2Abfu7%oC``jCCBqW}vv!0pJ>72qm~Y<0!9vllS;wgd3W ztO485z7Q=hjKFrls1OZhxb9j57;x={900E0ki(pCdw{D|oxC|Y$N{&5g36d^)N5!A zF!#Avu)9$mW$BZH3~(Fr^b38ianWGNchwQEP!TRc#Rye7dbd3@&{ky8!~w>Z%TtpX z6d$5_%I^|3wnE2gry7Hla49VOkI-yYKK_&H`FK!>2cso&yLCzfm_l#z z7l-g(zr8rggWK?4XT7+crcHwPN^NazDZT&Yve zC#cnGRd|>zlZb6J&@mN`KARMVq4La5RlGMUvPfgt!*9T-q&=*l-&2@t9!#s*GI_yaKQ**3)shbT`UF6YaC*1+FeZ+*QreM zVA4<6$yt427cMEWQEWL_TqU)-UjXxVY4BnPy*FvAyJffR^x?(Md2c`I9})q>i~aCk z($cN%u;Zvx-n(=s(xrD*!i(Ma-jyD_;K^Dyr-X88?dFte?u+iij@D`|o3(&>e_Bi> z+NaUFy@OMQXcS!T6;`StIx4sjsx1o5Y2c;?%#cURnrXsJ;?d9j`3W zOwmzV?^OoOkf~+*g?wB}-u)ikOqW*5kB{;f9K+tmb*u_E6X1o`2}PILqH3JwKW2Ua zTz=tDp3Y%=?K)>$XHt;&+htB32yAMpOG61aSELMzxC%hF6K-LE0ohKtxpHtqPVOQn z7nXAiD`117uTFY0dGP?8GFQvPB0n(Dah1H;)}_E;NLtOf&m9;2!GW$T<`FM~jA6~y znuv^p7)En&LQbX&J`$LqSS7N}kuJDeJvipgZO+RG+5bXvS7lbnYQPM+&XB9VmHbF3 z%;!1-I97lW=tjlBPDPF}WoG~{fbPlDX$8Xe`|ZaPY_E(j56b+>Ic%SK3Oc&4yl*NT zTL;)v&{lx83UCZ`n?bwQKTjC!$Of=h0*=8Zz$fDG1V-IrZyn0xBK~AO0IT=WhwR;D zSKm`^b*@eHv6TQEgH3>247_O|lt=59(AraDouf_wyt=n;aww0stZyoW_L=y%_{??m g+H}vVLw^Jq0D83(sH_n03jhEB07*qoM6N<$f=0JIbN~PV literal 0 HcmV?d00001 From e4d80d8ac62c0f7475fffb998cefc44e608c242f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 11:02:46 +0200 Subject: [PATCH 054/126] split local vs gallery extensions --- src/vs/code/node/cliProcessMain.ts | 2 +- .../common/extensionManagement.ts | 23 +++++++---- .../node/extensionGalleryService.ts | 26 +++++-------- .../node/extensionManagementService.ts | 25 ++++++------ .../node/extensionManagementUtil.ts | 8 ++-- .../extensions/common/extensionsInput.ts | 8 ++-- .../electron-browser/extensionEditor.ts | 2 +- .../electron-browser/extensionsActions.ts | 4 +- .../electron-browser/extensionsList.ts | 38 +++++++++---------- 9 files changed, 67 insertions(+), 69 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index f3cb2d252de..ee5c7e06f3d 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -98,7 +98,7 @@ class Main { console.log(localize('installing', "Installing...")); return this.extensionManagementService.install(extension).then(() => { - console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.manifest.version)); + console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.versions[0].version)); }); }); }); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 33532c32e30..781321bb5db 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -31,18 +31,25 @@ export interface IGalleryVersion { downloadHeaders: { [key: string]: string; }; } -export interface IGalleryMetadata { - publisherId: string; - publisherDisplayName: string; - installCount: number; - versions: IGalleryVersion[]; +export interface IExtensionIdentity { + name: string; + publisher: string; } export interface IGalleryExtension { id: string; - manifest: IExtensionManifest; - metadata: IGalleryMetadata; - path?: string; + name: string; + displayName: string; + publisherId: string; + publisher: string; + publisherDisplayName: string; + description: string; + installCount: number; + versions: IGalleryVersion[]; +} + +export interface IGalleryMetadata { + // TODO, do we need this?! } export interface IExtension { diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 214d6ffe840..02ab57ac665 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { IGalleryExtension, IExtensionManifest, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -171,24 +171,16 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr iconUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.Icons.Default` })); - const manifest: IExtensionManifest = { - name: galleryExtension.extensionName, - displayName: galleryExtension.displayName || galleryExtension.extensionName, - publisher: galleryExtension.publisher.publisherName, - version: versions[0].version, - engines: { vscode: void 0 }, // TODO: ugly - description: galleryExtension.shortDescription || '', - }; - return { id: galleryExtension.extensionId, - manifest, - metadata: { - publisherId: galleryExtension.publisher.publisherId, - publisherDisplayName: galleryExtension.publisher.displayName, - installCount: getInstallCount(galleryExtension.statistics), - versions - } + name: galleryExtension.extensionName, + displayName: galleryExtension.displayName, + publisherId: galleryExtension.publisher.publisherId, + publisher: galleryExtension.publisher.publisherName, + publisherDisplayName: galleryExtension.publisher.displayName, + description: galleryExtension.shortDescription || '', + installCount: getInstallCount(galleryExtension.statistics), + versions }; } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 919fdbdb390..0639742d9f5 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -41,7 +41,7 @@ function parseManifest(raw: string): TPromise<{ manifest: IExtensionManifest; me }); } -function validate(zipPath: string, extension?: IExtensionManifest, version = extension && extension.version): TPromise { +function validate(zipPath: string, extension?: IExtensionIdentity, version?: string): TPromise { return buffer(zipPath, 'extension/package.json') .then(buffer => parseManifest(buffer.toString('utf8'))) .then(({ manifest }) => { @@ -63,7 +63,7 @@ function validate(zipPath: string, extension?: IExtensionManifest, version = ext }); } -function getExtensionId(extension: IExtensionManifest, version = extension.version): string { +function getExtensionId(extension: IExtensionIdentity, version: string): string { return `${ extension.publisher }.${ extension.name }-${ version }`; } @@ -116,12 +116,11 @@ export class ExtensionManagementService implements IExtensionManagementService { } const extension = arg as IGalleryExtension; - const { manifest } = extension; - const id = getExtensionId(manifest); + const id = getExtensionId(extension, extension.versions[0].version); return this.isObsolete(id).then(obsolete => { if (obsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.name))); + return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); } return this.installFromGallery(arg); @@ -134,23 +133,23 @@ export class ExtensionManagementService implements IExtensionManagementService { const url = versionInfo.downloadUrl; const headers = versionInfo.downloadHeaders; const zipPath = path.join(tmpdir(), extension.id); - const id = getExtensionId(extension.manifest, version); + const id = getExtensionId(extension, version); return this.request(url) .then(opts => assign(opts, { headers })) .then(opts => download(zipPath, opts)) - .then(() => validate(zipPath, extension.manifest, version)) - .then(() => this.installValidExtension(zipPath, id, extension.metadata)); + .then(() => validate(zipPath, extension, version)) + .then(() => this.installValidExtension(zipPath, id)); }); } private getLastValidExtensionVersion(extension: IGalleryExtension): TPromise { - return this._getLastValidExtensionVersion(extension, extension.metadata.versions); + return this._getLastValidExtensionVersion(extension, extension.versions); } private _getLastValidExtensionVersion(extension: IGalleryExtension, versions: IGalleryVersion[]): TPromise { if (!versions.length) { - return TPromise.wrapError(new Error(nls.localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.manifest.displayName))); + return TPromise.wrapError(new Error(nls.localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.displayName || extension.name))); } const version = versions[0]; @@ -172,7 +171,7 @@ export class ExtensionManagementService implements IExtensionManagementService { } private installFromZip(zipPath: string): TPromise { - return validate(zipPath).then(manifest => this.installValidExtension(zipPath, getExtensionId(manifest))); + return validate(zipPath).then(manifest => this.installValidExtension(zipPath, getExtensionId(manifest, manifest.version))); } private installValidExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { @@ -238,7 +237,7 @@ export class ExtensionManagementService implements IExtensionManagementService { removeDeprecatedExtensions(): TPromise { const outdated = this.getOutdatedExtensionIds() - .then(extensions => extensions.map(e => getExtensionId(e.manifest))); + .then(extensions => extensions.map(e => getExtensionId(e.manifest, e.manifest.version))); const obsolete = this.getObsoleteExtensions() .then(obsolete => Object.keys(obsolete)); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 5ec8ff29733..187d5273792 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -5,11 +5,11 @@ 'use strict'; -import { IExtension, IExtensionManifest, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IExtensionIdentity, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TPromise } from 'vs/base/common/winjs.base'; import * as semver from 'semver'; -export function extensionEquals(one: IExtensionManifest, other: IExtensionManifest): boolean { +export function extensionEquals(one: IExtensionIdentity, other: IExtensionIdentity): boolean { return one.publisher === other.publisher && one.name === other.name; } @@ -38,8 +38,8 @@ export function getOutdatedExtensions(extensionsService: IExtensionManagementSer const available = result.firstPage; return available.map(extension => { - const local = installed.filter(local => extensionEquals(local.manifest, extension.manifest))[0]; - if (local && semver.lt(local.manifest.version, extension.manifest.version)) { + const local = installed.filter(local => extensionEquals(local.manifest, extension))[0]; + if (local && semver.lt(local.manifest.version, extension.versions[0].version)) { return local; } else { return null; diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 474132b1d10..2d1bac714c0 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,14 +7,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): IExtension | IGalleryExtension { return this._extension; } + get extension(): IGalleryExtension { return this._extension; } - constructor(private _extension: IExtension | IGalleryExtension) { + constructor(private _extension: IGalleryExtension) { super(); } @@ -23,7 +23,7 @@ export class ExtensionsInput extends EditorInput { } getName(): string { - return this.extension.manifest.displayName; + return this.extension.displayName; } matches(other: any): boolean { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 34f15382fe6..7f58a2d3c32 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -62,7 +62,7 @@ export class ExtensionEditor extends BaseEditor { addClass(this.body, 'loading'); this.body.innerHTML = ''; - const [version] = input.extension.metadata.versions; + const [version] = input.extension.versions; const headers = version.downloadHeaders; const promise = super.setInput(input, options) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 1614289b351..878c3e6289f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -127,7 +127,7 @@ export class InstallAction extends Action { this.enabled = false; return this.extensionManagementService.getInstalled() - .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension.manifest))) + .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension))) .then(isUpdate => { return this.extensionManagementService .install(extension) @@ -140,7 +140,7 @@ export class InstallAction extends Action { private onSuccess(extension: IGalleryExtension, isUpdate: boolean) { this.reportTelemetry(extension, isUpdate, true); this.messageService.show(Severity.Info, { - message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.manifest.displayName), + message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name), actions: [ CloseAction, this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now")) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index a7526bdc2e8..6f9f7494fb0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export interface ITemplateData { - extension: IExtension | IGalleryExtension; + extension: IGalleryExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,12 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -64,30 +64,30 @@ export class Renderer implements IPagedRenderer Date: Fri, 17 Jun 2016 11:10:18 +0200 Subject: [PATCH 055/126] complete separation between local and gallery --- .../common/extensionManagement.ts | 4 ++- .../node/extensionManagementService.ts | 7 +++- .../node/extensionManagementUtil.ts | 36 ++++++++++++------- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 781321bb5db..9b3ce03a04b 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -49,7 +49,9 @@ export interface IGalleryExtension { } export interface IGalleryMetadata { - // TODO, do we need this?! + id: string; + publisherId: string; + publisherDisplayName: string; } export interface IExtension { diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 0639742d9f5..c60a46309ee 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -134,12 +134,17 @@ export class ExtensionManagementService implements IExtensionManagementService { const headers = versionInfo.downloadHeaders; const zipPath = path.join(tmpdir(), extension.id); const id = getExtensionId(extension, version); + const metadata = { + id: extension.id, + publisherId: extension.publisherId, + publisherDisplayName: extension.publisherDisplayName + }; return this.request(url) .then(opts => assign(opts, { headers })) .then(opts => download(zipPath, opts)) .then(() => validate(zipPath, extension, version)) - .then(() => this.installValidExtension(zipPath, id)); + .then(() => this.installValidExtension(zipPath, id, metadata)); }); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 187d5273792..3d06d479f30 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IExtension, IExtensionIdentity, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionIdentity, IExtension, IGalleryExtension, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TPromise } from 'vs/base/common/winjs.base'; import * as semver from 'semver'; @@ -13,17 +13,29 @@ export function extensionEquals(one: IExtensionIdentity, other: IExtensionIdenti return one.publisher === other.publisher && one.name === other.name; } -export function getTelemetryData(extension: any): any { - return {}; - // TODO - // return { - // id: getExtensionId(extension), - // name: extension.name, - // galleryId: extension.galleryInformation ? extension.galleryInformation.id : null, - // publisherId: extension.galleryInformation ? extension.galleryInformation.publisherId : null, - // publisherName: extension.publisher, - // publisherDisplayName: extension.galleryInformation ? extension.galleryInformation.publisherDisplayName : null - // }; +export function getTelemetryData(extension: IExtension | IGalleryExtension): any { + const local = extension as IExtension; + const gallery = extension as IGalleryExtension; + + if (local.path) { + return { + id: `${ local.manifest.publisher }.${ local.manifest.name }`, + name: local.manifest.name, + galleryId: local.metadata ? local.metadata.id : null, + publisherId: local.metadata ? local.metadata.publisherId : null, + publisherName: local.manifest.publisher, + publisherDisplayName: local.metadata ? local.metadata.publisherDisplayName : null + }; + } else { + return { + id: `${ gallery.publisher }.${ gallery.name }`, + name: gallery.name, + galleryId: gallery.id, + publisherId: gallery.publisherId, + publisherName: gallery.publisher, + publisherDisplayName: gallery.publisherDisplayName + }; + } } export function getOutdatedExtensions(extensionsService: IExtensionManagementService, galleryService: IExtensionGalleryService): TPromise { From 746753fca5ef50c68f30b5ffcd90388e9d741caa Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 11:31:08 +0200 Subject: [PATCH 056/126] render local extensions --- .../extensions/common/extensionsInput.ts | 15 ++++-- .../electron-browser/extensionEditor.ts | 37 ++++++++----- .../electron-browser/extensionsList.ts | 54 +++++++++++++------ .../electron-browser/extensionsViewlet.ts | 12 ++--- 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 2d1bac714c0..41b7907d2ea 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,14 +7,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): IGalleryExtension { return this._extension; } + get extension(): IExtension | IGalleryExtension { return this._extension; } - constructor(private _extension: IGalleryExtension) { + constructor(private _extension: IExtension | IGalleryExtension) { super(); } @@ -23,7 +23,14 @@ export class ExtensionsInput extends EditorInput { } getName(): string { - return this.extension.displayName; + const local = this.extension as IExtension; + const gallery = this.extension as IGalleryExtension; + + if (local.path) { + return local.manifest.displayName || local.manifest.name; + } else { + return gallery.displayName || gallery.name; + } } matches(other: any): boolean { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 7f58a2d3c32..82199653bc0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -15,7 +15,7 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IGalleryExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -59,21 +59,32 @@ export class ExtensionEditor extends BaseEditor { setInput(input: ExtensionsInput, options: EditorOptions): TPromise { this.transientDisposables = dispose(this.transientDisposables); - addClass(this.body, 'loading'); this.body.innerHTML = ''; - const [version] = input.extension.versions; - const headers = version.downloadHeaders; + let promise = TPromise.as(null); + const extension = input.extension; + const local = extension as IExtension; + const gallery = extension as IGalleryExtension; - const promise = super.setInput(input, options) - .then(() => this.request(version.readmeUrl)) - .then(opts => assign(opts, { headers })) - .then(opts => downloadText(opts)) - .then(marked.parse) - .then(html => { - removeClass(this.body, 'loading'); - this.body.innerHTML = html; - }); + if (local.path) { + + + } else { + const [version] = gallery.versions; + const headers = version.downloadHeaders; + + addClass(this.body, 'loading'); + + promise = super.setInput(input, options) + .then(() => this.request(version.readmeUrl)) + .then(opts => assign(opts, { headers })) + .then(opts => downloadText(opts)) + .then(marked.parse) + .then(html => { + removeClass(this.body, 'loading'); + this.body.innerHTML = html; + }); + } this.transientDisposables.push(toDisposable(() => promise.cancel())); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 6f9f7494fb0..c039549cd09 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export interface ITemplateData { - extension: IGalleryExtension; + extension: IExtension | IGalleryExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,12 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -64,22 +64,42 @@ export class Renderer implements IPagedRenderer; + private list: PagedList; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -112,10 +112,10 @@ export class ExtensionsViewlet extends Viewlet { } private doSearch(text: string = ''): TPromise { - // return this.extensionService.getInstalled() - // .then(result => singlePageModel(result)) - return this.galleryService.query({ text }) - .then(result => new PagedModel(result)) + return this.extensionService.getInstalled() + .then(result => singlePageModel(result)) + // return this.galleryService.query({ text }) + // .then(result => new PagedModel(result)) .then(model => this.list.model = model); } From 80679b4c2dd977ccace0e5f64ca5b9cffdb039b5 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 12:30:29 +0200 Subject: [PATCH 057/126] extensions UI --- src/vs/base/common/paging.ts | 11 +++++ .../electron-browser/extensionsViewlet.ts | 41 ++++++++----------- .../media/extensionsViewlet.css | 6 +-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/vs/base/common/paging.ts b/src/vs/base/common/paging.ts index 5706b6c3c85..d0f923dc91b 100644 --- a/src/vs/base/common/paging.ts +++ b/src/vs/base/common/paging.ts @@ -105,6 +105,17 @@ export class PagedModel implements IPagedModel { } } +export class SinglePagePagedModel extends PagedModel { + constructor(elements: T[]) { + super({ + firstPage: elements, + total: elements.length, + pageSize: elements.length, + getPage: null + }); + } +} + /** * Similar to array.map, `mapPager` lets you map the elements of an * abstract paged collection to another type. diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 5fef91861eb..235f9f3a805 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -13,7 +13,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { Viewlet } from 'vs/workbench/browser/viewlet'; import { append, emmet as $ } from 'vs/base/browser/dom'; -import { PagedModel } from 'vs/base/common/paging'; +import { PagedModel, SinglePagePagedModel } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -23,15 +23,6 @@ import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -function singlePageModel(firstPage: T[]) { - return new PagedModel({ - firstPage, - total: firstPage.length, - pageSize: firstPage.length, - getPage: null - }); -} - export class ExtensionsViewlet extends Viewlet { static ID: string = 'workbench.viewlet.extensions'; @@ -61,9 +52,10 @@ export class ExtensionsViewlet extends Viewlet { parent.addClass('extensions-viewlet'); this.root = parent.getHTMLElement(); - const search = append(this.root, $('.search')); - this.searchBox = append(search, $('input.search-box')); - this.searchBox.placeholder = localize('searchExtensions', "Search Extensions"); + const header = append(this.root, $('.header')); + + this.searchBox = append(header, $('input.search-box')); + this.searchBox.placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); this.extensionsBox = append(this.root, $('.extensions')); const delegate = new Delegate(); @@ -103,19 +95,22 @@ export class ExtensionsViewlet extends Viewlet { } private triggerSearch(text: string = '', delay = 500): void { - this.list.model = singlePageModel([]); - - const promise = this.searchDelayer.trigger(() => this.doSearch(text), delay); - - const progressRunner = this.progressService.show(true); - always(promise, () => progressRunner.done()); + this.searchDelayer.trigger(() => this.doSearch(text), text ? delay : 0); } private doSearch(text: string = ''): TPromise { - return this.extensionService.getInstalled() - .then(result => singlePageModel(result)) - // return this.galleryService.query({ text }) - // .then(result => new PagedModel(result)) + const progressRunner = this.progressService.show(true); + let promise: TPromise>; + + if (text) { + promise = this.galleryService.query({ text }) + .then(result => new PagedModel(result)); + } else { + promise = this.extensionService.getInstalled() + .then(result => new SinglePagePagedModel(result)); + } + + return always(promise, () => progressRunner.done()) .then(model => this.list.model = model); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index f16e30a372d..9e118a0ebb9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -7,15 +7,15 @@ height: 100%; } -.extensions-viewlet > .search { +.extensions-viewlet > .header { height: 38px; box-sizing: border-box; padding: 5px 9px 5px 16px; } -.extensions-viewlet > .search > .search-box { +.extensions-viewlet > .header > .search-box { width: 100%; - height: 100%; + height: 26px; box-sizing: border-box; padding: 0 3px; } From bdb3bfefbe35051325155e2e0f240c19149fb217 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jun 2016 12:48:18 +0200 Subject: [PATCH 058/126] IExtension -> ILocalExtension --- .../common/extensionManagement.ts | 8 ++++---- .../common/extensionManagementIpc.ts | 12 ++++++------ .../node/extensionManagementService.ts | 12 ++++++------ .../node/extensionManagementUtil.ts | 8 ++++---- .../parts/extensions/common/extensionsInput.ts | 8 ++++---- .../extensions/electron-browser/extensionEditor.ts | 4 ++-- .../electron-browser/extensionTipsService.ts | 4 ++-- .../electron-browser/extensionsActions.ts | 10 +++++----- .../extensions/electron-browser/extensionsList.ts | 14 +++++++------- .../electron-browser/extensionsViewlet.ts | 6 +++--- 10 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 9b3ce03a04b..3b9230bee61 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -54,7 +54,7 @@ export interface IGalleryMetadata { publisherDisplayName: string; } -export interface IExtension { +export interface ILocalExtension { id: string; manifest: IExtensionManifest; metadata: IGalleryMetadata; @@ -95,15 +95,15 @@ export interface IExtensionManagementService { install(extension: IGalleryExtension): TPromise; install(zipPath: string): TPromise; - uninstall(extension: IExtension): TPromise; - getInstalled(includeDuplicateVersions?: boolean): TPromise; + uninstall(extension: ILocalExtension): TPromise; + getInstalled(includeDuplicateVersions?: boolean): TPromise; } export const IExtensionTipsService = createDecorator('extensionTipsService'); export interface IExtensionTipsService { serviceId: ServiceIdentifier; - getRecommendations(): TPromise; + getRecommendations(): TPromise; } export const ExtensionsLabel = nls.localize('extensions', "Extensions"); diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index e64fa00a6f5..6f9988fd0c0 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, IExtension, IGalleryExtension, DidInstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, DidInstallExtensionEvent } from './extensionManagement'; import Event from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -15,9 +15,9 @@ export interface IExtensionManagementChannel extends IChannel { call(command: 'event:onDidInstallExtension'): TPromise; call(command: 'event:onUninstallExtension'): TPromise; call(command: 'event:onDidUninstallExtension'): TPromise; - call(command: 'install', extensionOrPath: IExtension | string): TPromise; - call(command: 'uninstall', extension: IExtension): TPromise; - call(command: 'getInstalled', includeDuplicateVersions: boolean): TPromise; + call(command: 'install', extensionOrPath: ILocalExtension | string): TPromise; + call(command: 'uninstall', extension: ILocalExtension): TPromise; + call(command: 'getInstalled', includeDuplicateVersions: boolean): TPromise; call(command: string, arg: any): TPromise; } @@ -62,11 +62,11 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer return this.channel.call('install', arg); } - uninstall(extension: IExtension): TPromise { + uninstall(extension: ILocalExtension): TPromise { return this.channel.call('uninstall', extension); } - getInstalled(includeDuplicateVersions?: boolean): TPromise { + getInstalled(includeDuplicateVersions?: boolean): TPromise { return this.channel.call('getInstalled', includeDuplicateVersions); } } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index c60a46309ee..4fc842259b8 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, IExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -193,7 +193,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); } - uninstall(extension: IExtension): TPromise { + uninstall(extension: ILocalExtension): TPromise { const id = extension.id; const extensionPath = path.join(this.extensionsPath, id); @@ -206,7 +206,7 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => this._onDidUninstallExtension.fire(id)); } - getInstalled(includeDuplicateVersions: boolean = false): TPromise { + getInstalled(includeDuplicateVersions: boolean = false): TPromise { const all = this.getAllInstalled(); if (includeDuplicateVersions) { @@ -219,14 +219,14 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private getAllInstalled(): TPromise { + private getAllInstalled(): TPromise { const limiter = new Limiter(10); return this.getObsoleteExtensions() .then(obsolete => { return pfs.readdir(this.extensionsPath) .then(extensions => extensions.filter(id => !obsolete[id])) - .then(extensionIds => Promise.join(extensionIds.map(id => { + .then(extensionIds => Promise.join(extensionIds.map(id => { const extensionPath = path.join(this.extensionsPath, id); return limiter.queue( @@ -257,7 +257,7 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - private getOutdatedExtensionIds(): TPromise { + private getOutdatedExtensionIds(): TPromise { return this.getAllInstalled() .then(extensions => values(groupBy(extensions, p => `${ p.manifest.publisher }.${ p.manifest.name }`))) .then(versions => flatten(versions.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1)))); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 3d06d479f30..7dfb181595c 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IExtensionIdentity, IExtension, IGalleryExtension, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionIdentity, ILocalExtension, IGalleryExtension, IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { TPromise } from 'vs/base/common/winjs.base'; import * as semver from 'semver'; @@ -13,8 +13,8 @@ export function extensionEquals(one: IExtensionIdentity, other: IExtensionIdenti return one.publisher === other.publisher && one.name === other.name; } -export function getTelemetryData(extension: IExtension | IGalleryExtension): any { - const local = extension as IExtension; +export function getTelemetryData(extension: ILocalExtension | IGalleryExtension): any { + const local = extension as ILocalExtension; const gallery = extension as IGalleryExtension; if (local.path) { @@ -38,7 +38,7 @@ export function getTelemetryData(extension: IExtension | IGalleryExtension): any } } -export function getOutdatedExtensions(extensionsService: IExtensionManagementService, galleryService: IExtensionGalleryService): TPromise { +export function getOutdatedExtensions(extensionsService: IExtensionManagementService, galleryService: IExtensionGalleryService): TPromise { if (!galleryService.isEnabled()) { return TPromise.as([]); } diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 41b7907d2ea..299b579dc16 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,14 +7,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): IExtension | IGalleryExtension { return this._extension; } + get extension(): ILocalExtension | IGalleryExtension { return this._extension; } - constructor(private _extension: IExtension | IGalleryExtension) { + constructor(private _extension: ILocalExtension | IGalleryExtension) { super(); } @@ -23,7 +23,7 @@ export class ExtensionsInput extends EditorInput { } getName(): string { - const local = this.extension as IExtension; + const local = this.extension as ILocalExtension; const gallery = this.extension as IGalleryExtension; if (local.path) { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 82199653bc0..dbc56338e84 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -15,7 +15,7 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IExtension, IGalleryExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -63,7 +63,7 @@ export class ExtensionEditor extends BaseEditor { let promise = TPromise.as(null); const extension = input.extension; - const local = extension as IExtension; + const local = extension as ILocalExtension; const gallery = extension as IGalleryExtension; if (local.path) { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 276ffc285b8..e64d454366f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -8,7 +8,7 @@ import {forEach} from 'vs/base/common/collections'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {TPromise as Promise} from 'vs/base/common/winjs.base'; import {match} from 'vs/base/common/glob'; -import {IExtensionGalleryService, IExtensionTipsService, IExtension} from 'vs/platform/extensionManagement/common/extensionManagement'; +import {IExtensionGalleryService, IExtensionTipsService, ILocalExtension} from 'vs/platform/extensionManagement/common/extensionManagement'; import {IModelService} from 'vs/editor/common/services/modelService'; import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; @@ -62,7 +62,7 @@ export class ExtensionTipsService implements IExtensionTipsService { } } - getRecommendations(): Promise { + getRecommendations(): Promise { const ids = Object.keys(this._recommendations); return this._galleryService.query({ ids, pageSize: ids.length }) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 878c3e6289f..e3f7e291480 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IMessageService } from 'vs/platform/message/common/message'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; -import { IExtensionManagementService, IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; @@ -173,7 +173,7 @@ export class UninstallAction extends Action { super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true); } - run(extension: IExtension): TPromise { + run(extension: ILocalExtension): TPromise { const name = extension.manifest.displayName || extension.manifest.name; if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) { @@ -196,7 +196,7 @@ export class UninstallAction extends Action { }); } - private onSuccess(extension: IExtension) { + private onSuccess(extension: ILocalExtension) { const name = extension.manifest.displayName || extension.manifest.name; this.reportTelemetry(extension, true); @@ -209,12 +209,12 @@ export class UninstallAction extends Action { }); } - private onError(err: Error, extension: IExtension) { + private onError(err: Error, extension: ILocalExtension) { this.reportTelemetry(extension, false); this.messageService.show(Severity.Error, err); } - private reportTelemetry(extension: IExtension, success: boolean) { + private reportTelemetry(extension: ILocalExtension, success: boolean) { const data = assign(getTelemetryData(extension), { success }); this.telemetryService.publicLog('extensionGallery:uninstall', data); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index c039549cd09..52ad5dd0575 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; export interface ITemplateData { - extension: IExtension | IGalleryExtension; + extension: ILocalExtension | IGalleryExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,12 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -64,8 +64,8 @@ export class Renderer implements IPagedRenderer; + private list: PagedList; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -100,7 +100,7 @@ export class ExtensionsViewlet extends Viewlet { private doSearch(text: string = ''): TPromise { const progressRunner = this.progressService.show(true); - let promise: TPromise>; + let promise: TPromise>; if (text) { promise = this.galleryService.query({ text }) From 290822473b8070777f42dd929f2aa5d75774b906 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Sat, 18 Jun 2016 17:59:10 +0200 Subject: [PATCH 059/126] extensions model: first steps --- .../common/extensionManagement.ts | 10 +- .../node/extensionGalleryService.ts | 5 +- .../electron-browser/extensionsModel.ts | 117 ++++++++++++++++++ 3 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 3b9230bee61..81b22b88ef2 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -8,6 +8,7 @@ import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import Event from 'vs/base/common/event'; +import { IPager } from 'vs/base/common/paging'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export interface IExtensionManifest { @@ -70,17 +71,10 @@ export interface IQueryOptions { pageSize?: number; } -export interface IQueryResult { - firstPage: IGalleryExtension[]; - total: number; - pageSize: number; - getPage(pageNumber: number): TPromise; -} - export interface IExtensionGalleryService { serviceId: ServiceIdentifier; isEnabled(): boolean; - query(options?: IQueryOptions): TPromise; + query(options?: IQueryOptions): TPromise>; } export type DidInstallExtensionEvent = { id: string; error?: Error; }; diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 02ab57ac665..e8944b65fdd 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -4,11 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, IQueryResult } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IPager } from 'vs/base/common/paging'; import pkg from 'vs/platform/package'; import product from 'vs/platform/product'; @@ -208,7 +209,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { return !!this.extensionsGalleryUrl; } - query(options: IQueryOptions = {}): TPromise { + query(options: IQueryOptions = {}): TPromise> { if (!this.isEnabled()) { return TPromise.wrapError(new Error('No extension gallery service configured.')); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts new file mode 100644 index 00000000000..eed60e4e848 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/extensionsViewlet'; +import Event, { Emitter } from 'vs/base/common/event'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IPager } from 'vs/base/common/paging'; +import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; + +export enum ExtensionState { + Installing, + Installed, + Uninstalling, + Uninstalled +} + +export interface IExtension { + name: string; + publisher: string; + displayName: string; + version: string; + description: string; + iconUrl: string; +} + +class Extension implements IExtension { + + local: ILocalExtension; + gallery: IGalleryExtension; + + constructor() { + + } + + get name(): string { + return this.local ? this.local.manifest.name : this.gallery.name; + } + + get publisher(): string { + if (this.local) { + if (this.local.metadata && this.local.metadata.publisherDisplayName) { + return this.local.metadata.publisherDisplayName; + } + + return this.local.manifest.publisher; + } + + return this.gallery.publisherDisplayName || this.gallery.publisher; + } + + get displayName(): string { + if (this.local) { + return this.local.manifest.displayName || this.local.manifest.name; + } + + return this.gallery.displayName || this.gallery.name; + } + + get version(): string { + return this.local ? this.local.manifest.version : this.gallery.versions[0].version; + } + + get description(): string { + return this.local ? this.local.manifest.description : this.gallery.description; + } + + get iconUrl(): string { + if (this.local && this.local.manifest.icon) { + return `file://${ this.local.path }/${ this.local.manifest.icon }`; + } + + if (this.gallery && this.gallery.versions[0].iconUrl) { + return this.gallery.versions[0].iconUrl; + } + + return require.toUrl('./media/defaultIcon.png'); + } +} + +export class ExtensionsModel { + + private disposables: IDisposable[] = []; + + // private installing: Extension[]; + // private installed: Extension[]; + + private _onChange: Emitter; + get onChange(): Event { return this._onChange.event; } + + constructor( + @IExtensionManagementService private extensionService: IExtensionManagementService, + @IExtensionGalleryService private galleryService: IExtensionGalleryService + ) { + // todo + } + + getInstalled(): IExtension[] { + throw new Error('not implemented'); + } + + queryGallery(options: IQueryOptions = {}): TPromise> { + throw new Error('not implemented'); + } + + getState(extension: IExtension): ExtensionState { + throw new Error('not implemented'); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} From 877cd91459f38d991695e5c8d33d9ffbd66fa121 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Sun, 19 Jun 2016 09:24:57 +0200 Subject: [PATCH 060/126] missed reference --- src/vs/code/node/cliProcessMain.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index ee5c7e06f3d..7b93c1ce8b3 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -9,6 +9,7 @@ import pkg from 'vs/platform/package'; import { ParsedArgs } from 'vs/code/node/argv'; import { TPromise } from 'vs/base/common/winjs.base'; import { sequence } from 'vs/base/common/async'; +import { IPager } from 'vs/base/common/paging'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -17,7 +18,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IEventService } from 'vs/platform/event/common/event'; import { EventService } from 'vs/platform/event/common/eventService'; -import { IExtensionManagementService, IExtensionGalleryService, IQueryResult, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, IExtensionManifest, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { ITelemetryService, combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -77,7 +78,7 @@ class Main { } return this.extensionGalleryService.query({ ids: [id] }) - .then(null, err => { + .then>(null, err => { if (err.responseText) { try { const response = JSON.parse(err.responseText); From 9c94be39a9f180e6879a7e9b473c15344d1e8aed Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Sun, 19 Jun 2016 09:26:19 +0200 Subject: [PATCH 061/126] wip: adopt IExtension --- .../extensions/common/extensionsInput.ts | 21 ++++---- .../electron-browser/extensionEditor.ts | 13 +++-- .../electron-browser/extensionsList.ts | 53 ++++--------------- .../electron-browser/extensionsModel.ts | 41 ++++++++------ .../electron-browser/extensionsViewlet.ts | 13 +++-- 5 files changed, 56 insertions(+), 85 deletions(-) diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 299b579dc16..1bd0a1eee3e 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -7,14 +7,16 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; -import { ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; + +// TODO@joao: layer breaker +import { IExtension } from '../electron-browser/extensionsModel'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } - get extension(): ILocalExtension | IGalleryExtension { return this._extension; } + get extension(): IExtension { return this._extension; } - constructor(private _extension: ILocalExtension | IGalleryExtension) { + constructor(private _extension: IExtension) { super(); } @@ -23,14 +25,7 @@ export class ExtensionsInput extends EditorInput { } getName(): string { - const local = this.extension as ILocalExtension; - const gallery = this.extension as IGalleryExtension; - - if (local.path) { - return local.manifest.displayName || local.manifest.name; - } else { - return gallery.displayName || gallery.name; - } + return this.extension.displayName; } matches(other: any): boolean { @@ -39,7 +34,9 @@ export class ExtensionsInput extends EditorInput { } const otherExtensionInput = other as ExtensionsInput; - return this.extension.id === otherExtensionInput.extension.id; + + // TODO@joao is this correct? + return this.extension === otherExtensionInput.extension; } resolve(refresh?: boolean): TPromise { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index dbc56338e84..aa0f98a87f7 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -15,7 +15,8 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ILocalExtension, IGalleryExtension, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +// import { IExtension } from './extensionsModel'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -62,15 +63,13 @@ export class ExtensionEditor extends BaseEditor { this.body.innerHTML = ''; let promise = TPromise.as(null); - const extension = input.extension; - const local = extension as ILocalExtension; - const gallery = extension as IGalleryExtension; - - if (local.path) { + // const extension = input.extension; + if (1 === 1/*local.path*/) { + // TODO@joao } else { - const [version] = gallery.versions; + const version = null/*gallery.versions[0]*/; const headers = version.downloadHeaders; addClass(this.body, 'loading'); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 52ad5dd0575..3a063a47391 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -9,10 +9,10 @@ import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtension } from './extensionsModel'; export interface ITemplateData { - extension: ILocalExtension | IGalleryExtension; + extension: IExtension; element: HTMLElement; icon: HTMLImageElement; name: HTMLElement; @@ -21,12 +21,12 @@ export interface ITemplateData { description: HTMLElement; } -export class Delegate implements IDelegate { +export class Delegate implements IDelegate { getHeight() { return 62; } getTemplateId() { return 'extension'; } } -export class Renderer implements IPagedRenderer { +export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; get templates(): ITemplateData[] { return this._templates; } @@ -64,49 +64,14 @@ export class Renderer implements IPagedRenderer { + return this.extensionService.getInstalled() + .then(result => result.map(local => new Extension(local))); } queryGallery(options: IQueryOptions = {}): TPromise> { - throw new Error('not implemented'); + return this.galleryService.query(options) + .then(result => mapPager(result, gallery => new Extension(null, gallery))); } getState(extension: IExtension): ExtensionState { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 0449c67f877..b4e2208016a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -18,7 +18,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Delegate, Renderer } from './extensionsList'; -import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionsModel, IExtension } from './extensionsModel'; +import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -32,7 +33,8 @@ export class ExtensionsViewlet extends Viewlet { private root: HTMLElement; private searchBox: HTMLInputElement; private extensionsBox: HTMLElement; - private list: PagedList; + private model: ExtensionsModel; + private list: PagedList; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -45,6 +47,7 @@ export class ExtensionsViewlet extends Viewlet { super(ExtensionsViewlet.ID, telemetryService); this.searchDelayer = new ThrottledDelayer(500); this.disposables = []; + this.model = instantiationService.createInstance(ExtensionsModel); } create(parent: Builder): TPromise { @@ -100,13 +103,13 @@ export class ExtensionsViewlet extends Viewlet { private doSearch(text: string = ''): TPromise { const progressRunner = this.progressService.show(true); - let promise: TPromise>; + let promise: TPromise>; if (text) { - promise = this.galleryService.query({ text }) + promise = this.model.queryGallery({ text }) .then(result => new PagedModel(result)); } else { - promise = this.extensionService.getInstalled() + promise = this.model.getInstalled() .then(result => new SinglePagePagedModel(result)); } From 86a6759e6dae5616386c521033105d86fa6cdc27 Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Sun, 19 Jun 2016 18:22:36 +1000 Subject: [PATCH 062/126] fix : Standalone Monaco text edit validation --- src/vs/editor/browser/standalone/standaloneLanguages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index 2f833db0253..4ddedb0dc5b 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -396,7 +396,7 @@ class SuggestAdapter { let isSingleLine = (editRange.startLineNumber === editRange.endLineNumber); // invalid text edit - if (!isSingleLine || editRange.startColumn !== position.lineNumber) { + if (!isSingleLine || editRange.startLineNumber !== position.lineNumber) { console.warn('INVALID text edit, must be single line and on the same line'); continue; } From 21abbf9ad202f0e694cc38ab289952ee2423184a Mon Sep 17 00:00:00 2001 From: Georgios Kalpakas Date: Sun, 19 Jun 2016 11:47:11 +0300 Subject: [PATCH 063/126] docs(vscode.d.ts): fix typo ("a a" --> "a") --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 3817db9a13c..93cf6db550b 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2630,7 +2630,7 @@ declare namespace vscode { /** * A diagnostics collection is a container that manages a set of * [diagnostics](#Diagnostic). Diagnostics are always scopes to a - * a diagnostics collection and a resource. + * diagnostics collection and a resource. * * To get an instance of a `DiagnosticCollection` use * [createDiagnosticCollection](#languages.createDiagnosticCollection). From d4ac7e90ea9ea75b9045fea2832caf214c19ff9e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 10:55:42 +0200 Subject: [PATCH 064/126] arrays.index --- src/vs/base/common/arrays.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index f3f8fc6a201..bf47f5db4f9 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -232,4 +232,10 @@ export function fill(num: number, valueFn: () => T, arr: T[] = []): T[] { } return arr; +} + +export function index(array: T[], indexer: (t: T) => string): { [key: string]: T; } { + const result = Object.create(null); + array.forEach(t => result[indexer(t)] = t); + return result; } \ No newline at end of file From dc610b5ddd4bddd5b4e53b0b7543f5ddcb349f83 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 10:56:03 +0200 Subject: [PATCH 065/126] extension model: getInstalled, queryGallery --- .../electron-browser/extensionsModel.ts | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index a5aa877543c..cb8c469cbba 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -7,6 +7,7 @@ import 'vs/css!./media/extensionsViewlet'; import Event, { Emitter } from 'vs/base/common/event'; +import { index } from 'vs/base/common/arrays'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IPager, mapPager } from 'vs/base/common/paging'; @@ -92,7 +93,7 @@ export class ExtensionsModel { private disposables: IDisposable[] = []; // private installing: Extension[]; - // private installed: Extension[]; + private installed: Extension[] = []; private _onChange: Emitter; get onChange(): Event { return this._onChange.event; } @@ -105,13 +106,36 @@ export class ExtensionsModel { } getInstalled(): TPromise { - return this.extensionService.getInstalled() - .then(result => result.map(local => new Extension(local))); + return this.extensionService.getInstalled().then(result => { + const installedById = index(this.installed, e => e.local.id); + + this.installed = result.map(local => { + const id = local.path; + const extension = installedById[id] || new Extension(local); + extension.local = local; + return extension; + }); + + return this.installed; + }); } queryGallery(options: IQueryOptions = {}): TPromise> { - return this.galleryService.query(options) - .then(result => mapPager(result, gallery => new Extension(null, gallery))); + return this.galleryService.query(options).then(result => { + const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : ''); + + return mapPager(result, gallery => { + const id = gallery.id; + const installed = installedByGalleryId[id]; + + if (installed) { + installed.gallery = gallery; + return installed; + } + + return new Extension(null, gallery); + }); + }); } getState(extension: IExtension): ExtensionState { From cf51606d9c49887bc8f507d24ef4b129c60e1181 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 11:45:33 +0200 Subject: [PATCH 066/126] extensions model: react to events --- .../common/extensionManagement.ts | 5 ++- .../common/extensionManagementIpc.ts | 6 +-- .../node/extensionManagementService.ts | 39 +++++++++++------- .../electron-browser/extensionsModel.ts | 40 +++++++++++++++++-- .../electron-browser/extensionsViewlet.ts | 2 +- 5 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 81b22b88ef2..6d9779b2f0a 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -77,12 +77,13 @@ export interface IExtensionGalleryService { query(options?: IQueryOptions): TPromise>; } -export type DidInstallExtensionEvent = { id: string; error?: Error; }; +export type InstallExtensionEvent = { id: string; gallery?: IGalleryExtension; }; +export type DidInstallExtensionEvent = { id: string; local?: ILocalExtension; error?: Error; }; export interface IExtensionManagementService { serviceId: ServiceIdentifier; - onInstallExtension: Event; + onInstallExtension: Event; onDidInstallExtension: Event; onUninstallExtension: Event; onDidUninstallExtension: Event; diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 6f9988fd0c0..c4f4c7bcca8 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, DidInstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent } from './extensionManagement'; import Event from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -44,8 +44,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer constructor(private channel: IExtensionManagementChannel) { } - private _onInstallExtension = eventFromCall(this.channel, 'event:onInstallExtension'); - get onInstallExtension(): Event { return this._onInstallExtension; } + private _onInstallExtension = eventFromCall(this.channel, 'event:onInstallExtension'); + get onInstallExtension(): Event { return this._onInstallExtension; } private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); get onDidInstallExtension(): Event { return this._onDidInstallExtension; } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 4fc842259b8..36776a03836 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -15,7 +15,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { download, json, IRequestOptions } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -76,11 +76,11 @@ export class ExtensionManagementService implements IExtensionManagementService { private obsoleteFileLimiter: Limiter; private disposables: IDisposable[]; - private _onInstallExtension = new Emitter(); - onInstallExtension: Event = this._onInstallExtension.event; + private _onInstallExtension = new Emitter(); + onInstallExtension: Event = this._onInstallExtension.event; - private _onDidInstallExtension = new Emitter<{ id: string; error?: Error; }>(); - onDidInstallExtension: Event<{ id: string; error?: Error; }> = this._onDidInstallExtension.event; + private _onDidInstallExtension = new Emitter(); + onDidInstallExtension: Event = this._onDidInstallExtension.event; private _onUninstallExtension = new Emitter(); onUninstallExtension: Event = this._onUninstallExtension.event; @@ -112,11 +112,19 @@ export class ExtensionManagementService implements IExtensionManagementService { install(zipPath: string): TPromise; install(arg: any): TPromise { if (types.isString(arg)) { - return this.installFromZip(arg); + const zipPath = arg as string; + + return validate(zipPath).then(manifest => { + const id = getExtensionId(manifest, manifest.version); + this._onInstallExtension.fire({ id }); + + return this.installValidExtension(zipPath, id); + }); } const extension = arg as IGalleryExtension; const id = getExtensionId(extension, extension.versions[0].version); + this._onInstallExtension.fire({ id, gallery: extension }); return this.isObsolete(id).then(obsolete => { if (obsolete) { @@ -174,22 +182,25 @@ export class ExtensionManagementService implements IExtensionManagementService { return version; }); } - - private installFromZip(zipPath: string): TPromise { - return validate(zipPath).then(manifest => this.installValidExtension(zipPath, getExtensionId(manifest, manifest.version))); - } + id: string; + manifest: IExtensionManifest; + metadata: IGalleryMetadata; + path: string; private installValidExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { const extensionPath = path.join(this.extensionsPath, id); const manifestPath = path.join(extensionPath, 'package.json'); - this._onInstallExtension.fire(id); return extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }) .then(() => pfs.readFile(manifestPath, 'utf8')) .then(raw => parseManifest(raw)) - .then(({ manifest }) => assign(manifest, { __metadata: metadata })) - .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) - .then(() => this._onDidInstallExtension.fire({ id })) + .then(({ manifest }) => { + const local: ILocalExtension = { id, manifest, metadata, path: extensionPath }; + const rawManifest = assign(manifest, { __metadata: metadata }); + + return pfs.writeFile(manifestPath, JSON.stringify(rawManifest, null, '\t')) + .then(() => this._onDidInstallExtension.fire({ id, local })); + }) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index cb8c469cbba..8f3faf1c504 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -92,7 +92,7 @@ export class ExtensionsModel { private disposables: IDisposable[] = []; - // private installing: Extension[]; + private installing: { id: string; extension: Extension; }[]; private installed: Extension[] = []; private _onChange: Emitter; @@ -102,10 +102,11 @@ export class ExtensionsModel { @IExtensionManagementService private extensionService: IExtensionManagementService, @IExtensionGalleryService private galleryService: IExtensionGalleryService ) { - // todo + this.disposables.push(extensionService.onInstallExtension(({ id, gallery }) => this.onInstallExtension(id, gallery))); + this.disposables.push(extensionService.onDidInstallExtension(({ id, local, error }) => this.onDidInstallExtension(id, local, error))); } - getInstalled(): TPromise { + getLocal(): TPromise { return this.extensionService.getInstalled().then(result => { const installedById = index(this.installed, e => e.local.id); @@ -142,6 +143,39 @@ export class ExtensionsModel { throw new Error('not implemented'); } + private onInstallExtension(id: string, gallery: IGalleryExtension): void { + if (!gallery) { + return; + } + + let extension = this.installed.filter(e => (e.local.metadata && e.local.metadata.id) === gallery.id)[0]; + + if (!extension) { + extension = new Extension(null, gallery); + } + + extension.gallery = gallery; + this.installing.push({ id, extension }); + + this._onChange.fire(); + } + + private onDidInstallExtension(id: string, local: ILocalExtension, error: Error): void { + const installing = this.installing.filter(e => e.id === id)[0]; + + if (!installing) { + return; + } + + const extension = installing.extension; + extension.local = local; + + this.installing = this.installing.filter(e => e.id !== id); + this.installed.push(extension); + + this._onChange.fire(); + } + dispose(): void { this.disposables = dispose(this.disposables); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index b4e2208016a..42fdc935f46 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -109,7 +109,7 @@ export class ExtensionsViewlet extends Viewlet { promise = this.model.queryGallery({ text }) .then(result => new PagedModel(result)); } else { - promise = this.model.getInstalled() + promise = this.model.getLocal() .then(result => new SinglePagePagedModel(result)); } From a0e74e3bf609f4bcc7a4ad4fae8103b36c0bf4f0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 11:48:11 +0200 Subject: [PATCH 067/126] extension model: getState --- .../electron-browser/extensionsModel.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 8f3faf1c504..ecdb796436b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -16,7 +16,7 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, export enum ExtensionState { Installing, Installed, - Uninstalling, + // Uninstalling, Uninstalled } @@ -140,7 +140,21 @@ export class ExtensionsModel { } getState(extension: IExtension): ExtensionState { - throw new Error('not implemented'); + if (!(extension instanceof Extension)) { + return; + } + + const ext = extension as Extension; + + if (this.installed.indexOf(ext) > -1) { + return ExtensionState.Installed; + } + + if (this.installing.some(e => e.extension === ext)) { + return ExtensionState.Installing; + } + + return ExtensionState.Uninstalled; } private onInstallExtension(id: string, gallery: IGalleryExtension): void { From 65894b119c88491609c5444b4df4ee158aabd64a Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 12:25:34 +0200 Subject: [PATCH 068/126] wip: install action --- .../electron-browser/extensionsActions.ts | 346 +++++++++--------- .../electron-browser/extensionsList.ts | 22 +- .../electron-browser/extensionsModel.ts | 51 ++- .../electron-browser/extensionsViewlet.ts | 2 +- .../extensionsWorkbenchExtension.ts | 10 +- 5 files changed, 235 insertions(+), 196 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index e3f7e291480..7201b3c9f0f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -4,219 +4,229 @@ *--------------------------------------------------------------------------------------------*/ import nls = require('vs/nls'); -import { Promise, TPromise } from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; -import { assign } from 'vs/base/common/objects'; -import Severity from 'vs/base/common/severity'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; -import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +// import { assign } from 'vs/base/common/objects'; +// import Severity from 'vs/base/common/severity'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +// import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +// import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +// import { IMessageService } from 'vs/platform/message/common/message'; +// import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; +import { IExtension, ExtensionsModel, ExtensionState } from './extensionsModel'; +// import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; +// import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; -const CloseAction = new Action('action.close', nls.localize('close', "Close")); +// const CloseAction = new Action('action.close', nls.localize('close', "Close")); -export class ListExtensionsAction extends Action { +// export class ListExtensionsAction extends Action { - static ID = 'workbench.extensions.action.listExtensions'; - static LABEL = nls.localize('showInstalledExtensions', "Show Installed Extensions"); +// static ID = 'workbench.extensions.action.listExtensions'; +// static LABEL = nls.localize('showInstalledExtensions', "Show Installed Extensions"); - constructor( - id: string, - label: string, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, null, true); - } +// constructor( +// id: string, +// label: string, +// @IExtensionManagementService private extensionManagementService: IExtensionManagementService, +// @IQuickOpenService private quickOpenService: IQuickOpenService +// ) { +// super(id, label, null, true); +// } - run(): Promise { - return this.quickOpenService.show('ext '); - } +// run(): Promise { +// return this.quickOpenService.show('ext '); +// } - protected isEnabled(): boolean { - return true; - } -} +// protected isEnabled(): boolean { +// return true; +// } +// } -export class InstallExtensionAction extends Action { +// export class InstallExtensionAction extends Action { - static ID = 'workbench.extensions.action.installExtension'; - static LABEL = nls.localize('installExtension', "Install Extension"); +// static ID = 'workbench.extensions.action.installExtension'; +// static LABEL = nls.localize('installExtension', "Install Extension"); - constructor( - id: string, - label: string, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, null, true); - } +// constructor( +// id: string, +// label: string, +// @IExtensionManagementService private extensionManagementService: IExtensionManagementService, +// @IQuickOpenService private quickOpenService: IQuickOpenService +// ) { +// super(id, label, null, true); +// } - run(): Promise { - return this.quickOpenService.show('ext install '); - } +// run(): Promise { +// return this.quickOpenService.show('ext install '); +// } - protected isEnabled(): boolean { - return true; - } -} +// protected isEnabled(): boolean { +// return true; +// } +// } -export class ListOutdatedExtensionsAction extends Action { +// export class ListOutdatedExtensionsAction extends Action { - static ID = 'workbench.extensions.action.listOutdatedExtensions'; - static LABEL = nls.localize('showOutdatedExtensions', "Show Outdated Extensions"); +// static ID = 'workbench.extensions.action.listOutdatedExtensions'; +// static LABEL = nls.localize('showOutdatedExtensions', "Show Outdated Extensions"); - constructor( - id: string, - label: string, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, null, true); - } +// constructor( +// id: string, +// label: string, +// @IExtensionManagementService private extensionManagementService: IExtensionManagementService, +// @IQuickOpenService private quickOpenService: IQuickOpenService +// ) { +// super(id, label, null, true); +// } - run(): Promise { - return this.quickOpenService.show('ext update '); - } +// run(): Promise { +// return this.quickOpenService.show('ext update '); +// } - protected isEnabled(): boolean { - return true; - } -} +// protected isEnabled(): boolean { +// return true; +// } +// } -export class ListSuggestedExtensionsAction extends Action { +// export class ListSuggestedExtensionsAction extends Action { - static ID = 'workbench.extensions.action.listSuggestedExtensions'; - static LABEL = nls.localize('showExtensionRecommendations', "Show Extension Recommendations"); +// static ID = 'workbench.extensions.action.listSuggestedExtensions'; +// static LABEL = nls.localize('showExtensionRecommendations', "Show Extension Recommendations"); - constructor( - id: string, - label: string, - @IExtensionManagementService private extensionManagementService: IExtensionManagementService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, null, true); - } +// constructor( +// id: string, +// label: string, +// @IExtensionManagementService private extensionManagementService: IExtensionManagementService, +// @IQuickOpenService private quickOpenService: IQuickOpenService +// ) { +// super(id, label, null, true); +// } - run(): Promise { - return this.quickOpenService.show('ext recommend '); - } +// run(): Promise { +// return this.quickOpenService.show('ext recommend '); +// } - protected isEnabled(): boolean { - return true; - } -} +// protected isEnabled(): boolean { +// return true; +// } +// } export class InstallAction extends Action { - constructor( - label: string, - @IQuickOpenService protected quickOpenService: IQuickOpenService, - @IExtensionManagementService protected extensionManagementService: IExtensionManagementService, - @IMessageService protected messageService: IMessageService, - @ITelemetryService protected telemetryService: ITelemetryService, - @IInstantiationService protected instantiationService: IInstantiationService - ) { - super('extensions.install', label, 'octicon octicon-cloud-download', true); + private disposables: IDisposable[] = []; + + constructor(private model: ExtensionsModel, private extension: IExtension) { + super('extensions.install', nls.localize('installAction', "Install"), 'octicon octicon-cloud-download', false); + + this.disposables.push(this.model.onChange(() => this.updateEnablement())); + this.updateEnablement(); } - run(extension: IGalleryExtension): TPromise { - this.enabled = false; - - return this.extensionManagementService.getInstalled() - .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension))) - .then(isUpdate => { - return this.extensionManagementService - .install(extension) - .then(() => this.onSuccess(extension, isUpdate), err => this.onError(err, extension, isUpdate)) - .then(() => this.enabled = true) - .then(() => null); - }); + private updateEnablement(): void { + this.enabled = this.extension.state === ExtensionState.Uninstalled; } - private onSuccess(extension: IGalleryExtension, isUpdate: boolean) { - this.reportTelemetry(extension, isUpdate, true); - this.messageService.show(Severity.Info, { - message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name), - actions: [ - CloseAction, - this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now")) - ] - }); + run(): TPromise { + return this.model.install(this.extension); + + // this.enabled = false; + + // return this.extensionManagementService.getInstalled() + // .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension))) + // .then(isUpdate => { + // return this.extensionManagementService + // .install(extension) + // .then(() => this.onSuccess(extension, isUpdate), err => this.onError(err, extension, isUpdate)) + // .then(() => this.enabled = true) + // .then(() => null); + // }); } - private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) { - this.reportTelemetry(extension, isUpdate, false); - this.messageService.show(Severity.Error, err); - } + // private onSuccess(extension: IGalleryExtension, isUpdate: boolean) { + // this.reportTelemetry(extension, isUpdate, true); + // this.messageService.show(Severity.Info, { + // message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name), + // actions: [ + // CloseAction, + // this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now")) + // ] + // }); + // } - private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) { - const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install'; - const data = assign(getTelemetryData(extension), { success }); + // private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) { + // this.reportTelemetry(extension, isUpdate, false); + // this.messageService.show(Severity.Error, err); + // } - this.telemetryService.publicLog(event, data); + // private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) { + // const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install'; + // const data = assign(getTelemetryData(extension), { success }); + + // this.telemetryService.publicLog(event, data); + // } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); } } -export class UninstallAction extends Action { +// export class UninstallAction extends Action { - constructor( - @IQuickOpenService protected quickOpenService: IQuickOpenService, - @IExtensionManagementService protected extensionManagementService: IExtensionManagementService, - @IMessageService protected messageService: IMessageService, - @ITelemetryService protected telemetryService: ITelemetryService, - @IInstantiationService protected instantiationService: IInstantiationService - ) { - super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true); - } +// constructor( +// @IQuickOpenService protected quickOpenService: IQuickOpenService, +// @IExtensionManagementService protected extensionManagementService: IExtensionManagementService, +// @IMessageService protected messageService: IMessageService, +// @ITelemetryService protected telemetryService: ITelemetryService, +// @IInstantiationService protected instantiationService: IInstantiationService +// ) { +// super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true); +// } - run(extension: ILocalExtension): TPromise { - const name = extension.manifest.displayName || extension.manifest.name; +// run(extension: ILocalExtension): TPromise { +// const name = extension.manifest.displayName || extension.manifest.name; - if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) { - return TPromise.as(null); - } +// if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) { +// return TPromise.as(null); +// } - this.enabled = false; +// this.enabled = false; - return this.extensionManagementService.getInstalled().then(localExtensions => { - const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest)); +// return this.extensionManagementService.getInstalled().then(localExtensions => { +// const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest)); - if (!local) { - return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name)); - } +// if (!local) { +// return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name)); +// } - return this.extensionManagementService.uninstall(local) - .then(() => this.onSuccess(local), err => this.onError(err, local)) - .then(() => this.enabled = true) - .then(() => null); - }); - } +// return this.extensionManagementService.uninstall(local) +// .then(() => this.onSuccess(local), err => this.onError(err, local)) +// .then(() => this.enabled = true) +// .then(() => null); +// }); +// } - private onSuccess(extension: ILocalExtension) { - const name = extension.manifest.displayName || extension.manifest.name; - this.reportTelemetry(extension, true); +// private onSuccess(extension: ILocalExtension) { +// const name = extension.manifest.displayName || extension.manifest.name; +// this.reportTelemetry(extension, true); - this.messageService.show(Severity.Info, { - message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", name), - actions: [ - CloseAction, - this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow2', "Restart Now")) - ] - }); - } +// this.messageService.show(Severity.Info, { +// message: nls.localize('success-uninstalled', "'{0}' was successfully uninstalled. Restart to deactivate it.", name), +// actions: [ +// CloseAction, +// this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow2', "Restart Now")) +// ] +// }); +// } - private onError(err: Error, extension: ILocalExtension) { - this.reportTelemetry(extension, false); - this.messageService.show(Severity.Error, err); - } +// private onError(err: Error, extension: ILocalExtension) { +// this.reportTelemetry(extension, false); +// this.messageService.show(Severity.Error, err); +// } - private reportTelemetry(extension: ILocalExtension, success: boolean) { - const data = assign(getTelemetryData(extension), { success }); +// private reportTelemetry(extension: ILocalExtension, success: boolean) { +// const data = assign(getTelemetryData(extension), { success }); - this.telemetryService.publicLog('extensionGallery:uninstall', data); - } -} +// this.telemetryService.publicLog('extensionGallery:uninstall', data); +// } +// } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 3a063a47391..3b67622cdb8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -6,10 +6,13 @@ 'use strict'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; -import { IExtension } from './extensionsModel'; +import { IExtension, ExtensionsModel } from './extensionsModel'; +import { InstallAction } from './extensionsActions'; export interface ITemplateData { extension: IExtension; @@ -19,6 +22,8 @@ export interface ITemplateData { version: HTMLElement; author: HTMLElement; description: HTMLElement; + actionbar: ActionBar; + disposables: IDisposable[]; } export class Delegate implements IDelegate { @@ -32,6 +37,7 @@ export class Renderer implements IPagedRenderer { get templates(): ITemplateData[] { return this._templates; } constructor( + private model: ExtensionsModel, @IInstantiationService private instantiationService: IInstantiationService ) { this._templates = []; @@ -48,13 +54,17 @@ export class Renderer implements IPagedRenderer { const version = append(header, $('span.version.ellipsis')); const author = append(header, $('span.author.ellipsis')); const description = append(details, $('.description.ellipsis')); - const result = { extension: null, element, icon, name, version, author, description }; + const actionbar = new ActionBar(details); + const disposables = []; + const result = { extension: null, element, icon, name, version, author, description, actionbar, disposables }; this._templates.push(result); return result; } renderPlaceholder(index: number, data: ITemplateData): void { + data.disposables = dispose(data.disposables); + addClass(data.element, 'loading'); data.extension = null; data.icon.src = ''; @@ -62,17 +72,21 @@ export class Renderer implements IPagedRenderer { data.version.textContent = ''; data.author.textContent = ''; data.description.textContent = ''; + data.actionbar.clear(); } renderElement(extension: IExtension, index: number, data: ITemplateData): void { - data.extension = extension; - removeClass(data.element, 'loading'); + data.disposables = dispose(data.disposables); + removeClass(data.element, 'loading'); + data.extension = extension; data.icon.src = extension.iconUrl; data.name.textContent = extension.displayName; data.version.textContent = extension.version; data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; + data.actionbar.clear(); + data.actionbar.push(new InstallAction(this.model, extension)); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index ecdb796436b..3c7682e334e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -21,6 +21,7 @@ export enum ExtensionState { } export interface IExtension { + state: ExtensionState; name: string; displayName: string; publisher: string; @@ -30,14 +31,17 @@ export interface IExtension { iconUrl: string; } +interface IExtensionStateProvider { + (extension: Extension): ExtensionState; +} + class Extension implements IExtension { constructor( + private stateProvider: IExtensionStateProvider, public local: ILocalExtension, public gallery: IGalleryExtension = null - ) { - - } + ) {} get name(): string { return this.local ? this.local.manifest.name : this.gallery.name; @@ -86,22 +90,28 @@ class Extension implements IExtension { return require.toUrl('./media/defaultIcon.png'); } + + get state(): ExtensionState { + return this.stateProvider(this); + } } export class ExtensionsModel { private disposables: IDisposable[] = []; - private installing: { id: string; extension: Extension; }[]; + private stateProvider: IExtensionStateProvider; + private installing: { id: string; extension: Extension; }[] = []; private installed: Extension[] = []; - private _onChange: Emitter; + private _onChange: Emitter = new Emitter(); get onChange(): Event { return this._onChange.event; } constructor( @IExtensionManagementService private extensionService: IExtensionManagementService, @IExtensionGalleryService private galleryService: IExtensionGalleryService ) { + this.stateProvider = ext => this.getExtensionState(ext); this.disposables.push(extensionService.onInstallExtension(({ id, gallery }) => this.onInstallExtension(id, gallery))); this.disposables.push(extensionService.onDidInstallExtension(({ id, local, error }) => this.onDidInstallExtension(id, local, error))); } @@ -112,7 +122,7 @@ export class ExtensionsModel { this.installed = result.map(local => { const id = local.path; - const extension = installedById[id] || new Extension(local); + const extension = installedById[id] || new Extension(this.stateProvider, local); extension.local = local; return extension; }); @@ -134,27 +144,24 @@ export class ExtensionsModel { return installed; } - return new Extension(null, gallery); + return new Extension(this.stateProvider, null, gallery); }); }); } - getState(extension: IExtension): ExtensionState { + install(extension: IExtension): TPromise { if (!(extension instanceof Extension)) { return; } const ext = extension as Extension; + const gallery = ext.gallery; - if (this.installed.indexOf(ext) > -1) { - return ExtensionState.Installed; + if (!gallery) { + return TPromise.wrapError(new Error('Missing gallery')); } - if (this.installing.some(e => e.extension === ext)) { - return ExtensionState.Installing; - } - - return ExtensionState.Uninstalled; + return this.extensionService.install(gallery); } private onInstallExtension(id: string, gallery: IGalleryExtension): void { @@ -165,7 +172,7 @@ export class ExtensionsModel { let extension = this.installed.filter(e => (e.local.metadata && e.local.metadata.id) === gallery.id)[0]; if (!extension) { - extension = new Extension(null, gallery); + extension = new Extension(this.stateProvider, null, gallery); } extension.gallery = gallery; @@ -190,6 +197,18 @@ export class ExtensionsModel { this._onChange.fire(); } + private getExtensionState(extension: Extension): ExtensionState { + if (this.installed.indexOf(extension) > -1) { + return ExtensionState.Installed; + } + + if (this.installing.some(e => e.extension === extension)) { + return ExtensionState.Installing; + } + + return ExtensionState.Uninstalled; + } + dispose(): void { this.disposables = dispose(this.disposables); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 42fdc935f46..f8dc13d690b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -62,7 +62,7 @@ export class ExtensionsViewlet extends Viewlet { this.extensionsBox = append(this.root, $('.extensions')); const delegate = new Delegate(); - const renderer = this.instantiationService.createInstance(Renderer); + const renderer = this.instantiationService.createInstance(Renderer, this.model); this.list = new PagedList(this.extensionsBox, delegate, [renderer]); this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts index 74b0fa6de43..7d791c17894 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts @@ -5,18 +5,14 @@ import nls = require('vs/nls'); import errors = require('vs/base/common/errors'); -import platform = require('vs/platform/platform'); import { Promise } from 'vs/base/common/winjs.base'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ExtensionsLabel } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; -import wbaregistry = require('vs/workbench/common/actionRegistry'); -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ListExtensionsAction } from './extensionsActions'; import {ipcRenderer as ipc} from 'electron'; interface IInstallExtensionsRequest { @@ -41,8 +37,8 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution { this.install(options.extensionsToInstall).done(null, errors.onUnexpectedError); } - const actionRegistry = ( platform.Registry.as(wbaregistry.Extensions.WorkbenchActions)); - actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel); + // const actionRegistry = ( platform.Registry.as(wbaregistry.Extensions.WorkbenchActions)); + // actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel); } private registerListeners(): void { From 12ef63a658f8a9ca50de9478cc046029a593693b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 12:39:45 +0200 Subject: [PATCH 069/126] wip: uninstall extension --- .../electron-browser/extensionsActions.ts | 69 +++++++++++-------- .../electron-browser/extensionsList.ts | 13 +++- .../electron-browser/extensionsModel.ts | 35 ++++++++++ 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 7201b3c9f0f..894a03e72b0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -123,7 +123,7 @@ export class InstallAction extends Action { } private updateEnablement(): void { - this.enabled = this.extension.state === ExtensionState.Uninstalled; + this.enabled = this.model.canInstall(this.extension) && this.extension.state === ExtensionState.Uninstalled; } run(): TPromise { @@ -171,40 +171,46 @@ export class InstallAction extends Action { } } -// export class UninstallAction extends Action { +export class UninstallAction extends Action { -// constructor( -// @IQuickOpenService protected quickOpenService: IQuickOpenService, -// @IExtensionManagementService protected extensionManagementService: IExtensionManagementService, -// @IMessageService protected messageService: IMessageService, -// @ITelemetryService protected telemetryService: ITelemetryService, -// @IInstantiationService protected instantiationService: IInstantiationService -// ) { -// super('extensions.uninstall', nls.localize('uninstall', "Uninstall Extension"), 'octicon octicon-x', true); -// } + private disposables: IDisposable[] = []; -// run(extension: ILocalExtension): TPromise { -// const name = extension.manifest.displayName || extension.manifest.name; + constructor(private model: ExtensionsModel, private extension: IExtension) { + super('extensions.uninstall', nls.localize('uninstall', "Uninstall"), 'octicon octicon-x', false); -// if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", name))) { -// return TPromise.as(null); -// } + this.disposables.push(this.model.onChange(() => this.updateEnablement())); + this.updateEnablement(); + } -// this.enabled = false; + private updateEnablement(): void { + this.enabled = this.extension.state === ExtensionState.Installed; + } -// return this.extensionManagementService.getInstalled().then(localExtensions => { -// const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest)); + run(): TPromise { + // const name = extension.manifest.displayName || extension.manifest.name; -// if (!local) { -// return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name)); -// } + if (!window.confirm(nls.localize('deleteSure', "Are you sure you want to uninstall '{0}'?", this.extension.displayName))) { + return TPromise.as(null); + } -// return this.extensionManagementService.uninstall(local) -// .then(() => this.onSuccess(local), err => this.onError(err, local)) -// .then(() => this.enabled = true) -// .then(() => null); -// }); -// } + + return this.model.uninstall(this.extension); + + // this.enabled = false; + + // return this.extensionManagementService.getInstalled().then(localExtensions => { + // const [local] = localExtensions.filter(local => extensionEquals(local.manifest, extension.manifest)); + + // if (!local) { + // return TPromise.wrapError(nls.localize('notFound', "Extension '{0}' not installed.", name)); + // } + + // return this.extensionManagementService.uninstall(local) + // .then(() => this.onSuccess(local), err => this.onError(err, local)) + // .then(() => this.enabled = true) + // .then(() => null); + // }); + } // private onSuccess(extension: ILocalExtension) { // const name = extension.manifest.displayName || extension.manifest.name; @@ -229,4 +235,9 @@ export class InstallAction extends Action { // this.telemetryService.publicLog('extensionGallery:uninstall', data); // } -// } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 3b67622cdb8..0387c2a557d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, ExtensionsModel } from './extensionsModel'; -import { InstallAction } from './extensionsActions'; +import { InstallAction, UninstallAction } from './extensionsActions'; export interface ITemplateData { extension: IExtension; @@ -31,6 +31,8 @@ export class Delegate implements IDelegate { getTemplateId() { return 'extension'; } } +const actionOptions = { icon: true, label: false }; + export class Renderer implements IPagedRenderer { private _templates: ITemplateData[]; @@ -86,7 +88,14 @@ export class Renderer implements IPagedRenderer { data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; data.actionbar.clear(); - data.actionbar.push(new InstallAction(this.model, extension)); + + const installAction = new InstallAction(this.model, extension); + data.actionbar.push(installAction, actionOptions); + data.disposables.push(installAction); + + const uninstallAction = new UninstallAction(this.model, extension); + data.actionbar.push(uninstallAction, actionOptions); + data.disposables.push(uninstallAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 3c7682e334e..a39745305a0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -114,6 +114,7 @@ export class ExtensionsModel { this.stateProvider = ext => this.getExtensionState(ext); this.disposables.push(extensionService.onInstallExtension(({ id, gallery }) => this.onInstallExtension(id, gallery))); this.disposables.push(extensionService.onDidInstallExtension(({ id, local, error }) => this.onDidInstallExtension(id, local, error))); + this.disposables.push(extensionService.onUninstallExtension((id) => this.onUninstallExtension(id))); } getLocal(): TPromise { @@ -149,6 +150,14 @@ export class ExtensionsModel { }); } + canInstall(extension: IExtension): boolean { + if (!(extension instanceof Extension)) { + return; + } + + return !!(extension as Extension).gallery; + } + install(extension: IExtension): TPromise { if (!(extension instanceof Extension)) { return; @@ -164,6 +173,21 @@ export class ExtensionsModel { return this.extensionService.install(gallery); } + uninstall(extension: IExtension): TPromise { + if (!(extension instanceof Extension)) { + return; + } + + const ext = extension as Extension; + const local = ext.local; + + if (!local) { + return TPromise.wrapError(new Error('Missing local')); + } + + return this.extensionService.uninstall(local); + } + private onInstallExtension(id: string, gallery: IGalleryExtension): void { if (!gallery) { return; @@ -197,6 +221,17 @@ export class ExtensionsModel { this._onChange.fire(); } + private onUninstallExtension(id: string): void { + const previousLength = this.installed.length; + this.installed = this.installed.filter(e => e.local.id !== id); + + if (previousLength === this.installed.length) { + return; + } + + this._onChange.fire(); + } + private getExtensionState(extension: Extension): ExtensionState { if (this.installed.indexOf(extension) > -1) { return ExtensionState.Installed; From 836ee2b4316403c65d842574169dacfe710fabf5 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 12:56:53 +0200 Subject: [PATCH 070/126] extensions modle: on did update --- .../extensions/electron-browser/extensionsModel.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index a39745305a0..5ca24b953cc 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -216,7 +216,15 @@ export class ExtensionsModel { extension.local = local; this.installing = this.installing.filter(e => e.id !== id); - this.installed.push(extension); + + const galleryId = local.metadata && local.metadata.id; + const installed = this.installed.filter(e => (e.local.metadata && e.local.metadata.id) === galleryId)[0]; + + if (galleryId && installed) { + installed.local = local; + } else { + this.installed.push(extension); + } this._onChange.fire(); } From e42b24c6655ec51f762bdcf7e20a81b726a83fd1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 14:23:31 +0200 Subject: [PATCH 071/126] UI interactions --- .../electron-browser/extensionsViewlet.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index f8dc13d690b..0979f9c3dc2 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -11,6 +11,8 @@ import { ThrottledDelayer, always } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; import { Viewlet } from 'vs/workbench/browser/viewlet'; import { append, emmet as $ } from 'vs/base/browser/dom'; import { PagedModel, SinglePagePagedModel } from 'vs/base/common/paging'; @@ -28,13 +30,13 @@ export class ExtensionsViewlet extends Viewlet { static ID: string = 'workbench.viewlet.extensions'; - private disposables: IDisposable[]; private searchDelayer: ThrottledDelayer; private root: HTMLElement; private searchBox: HTMLInputElement; private extensionsBox: HTMLElement; private model: ExtensionsModel; private list: PagedList; + private disposables: IDisposable[] = []; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -46,7 +48,6 @@ export class ExtensionsViewlet extends Viewlet { ) { super(ExtensionsViewlet.ID, telemetryService); this.searchDelayer = new ThrottledDelayer(500); - this.disposables = []; this.model = instantiationService.createInstance(ExtensionsModel); } @@ -65,7 +66,8 @@ export class ExtensionsViewlet extends Viewlet { const renderer = this.instantiationService.createInstance(Renderer, this.model); this.list = new PagedList(this.extensionsBox, delegate, [renderer]); - this.searchBox.oninput = () => this.triggerSearch(this.searchBox.value); + this.searchBox.onkeydown = e => this.onSearchKeyDown(new StandardKeyboardEvent(e)); + this.searchBox.oninput = () => this.triggerSearch(); this.list.onSelectionChange(e => { const [extension] = e.elements; @@ -83,8 +85,11 @@ export class ExtensionsViewlet extends Viewlet { setVisible(visible:boolean): TPromise { return super.setVisible(visible).then(() => { if (visible) { - this.searchBox.value = ''; - this.triggerSearch('', 0); + this.searchBox.focus(); + this.searchBox.setSelectionRange(0,this.searchBox.value.length); + this.triggerSearch(0); + } else { + this.list.model = new SinglePagePagedModel([]); } }); } @@ -97,7 +102,8 @@ export class ExtensionsViewlet extends Viewlet { this.list.layout(height - 38); } - private triggerSearch(text: string = '', delay = 500): void { + private triggerSearch(delay = 500): void { + const text = this.searchBox.value; this.searchDelayer.trigger(() => this.doSearch(text), text ? delay : 0); } @@ -117,6 +123,13 @@ export class ExtensionsViewlet extends Viewlet { .then(model => this.list.model = model); } + private onSearchKeyDown(e: StandardKeyboardEvent): void { + if (e.keyCode === KeyCode.Escape) { + this.searchBox.value = ''; + this.triggerSearch(0); + } + } + dispose(): void { this.disposables = dispose(this.disposables); super.dispose(); From d51eedec4b1090cb1eb7ca364bf7656e0c242035 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 14:48:58 +0200 Subject: [PATCH 072/126] combined install action --- .../electron-browser/extensionsActions.ts | 48 +++++++++++++++++++ .../electron-browser/extensionsList.ts | 8 +--- .../electron-browser/extensionsModel.ts | 7 ++- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 894a03e72b0..4948560ebb1 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -241,3 +241,51 @@ export class UninstallAction extends Action { this.disposables = dispose(this.disposables); } } + +export class CombinedInstallAction extends Action { + + private installAction: InstallAction; + private uninstallAction: UninstallAction; + private disposables: IDisposable[] = []; + + constructor(private model: ExtensionsModel, private extension: IExtension) { + super('extensions.combinedInstall', '', '', false); + + this.installAction = new InstallAction(model, extension); + this.uninstallAction = new UninstallAction(model, extension); + this.disposables.push(this.installAction, this.uninstallAction); + + this.disposables.push(this.installAction.addListener2(Action.ENABLED, () => this.update())); + this.disposables.push(this.uninstallAction.addListener2(Action.ENABLED, () => this.update())); + this.update(); + } + + private update(): void { + if (this.installAction.enabled) { + this.enabled = true; + this.label = this.installAction.label; + this.class = this.installAction.class; + } else if (this.uninstallAction.enabled) { + this.enabled = true; + this.label = this.uninstallAction.label; + this.class = this.uninstallAction.class; + } else { + this.enabled = false; + } + } + + run(): TPromise { + if (this.installAction.enabled) { + return this.installAction.run(); + } else if (this.uninstallAction.enabled) { + return this.uninstallAction.run(); + } + + return TPromise.as(null); + } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 0387c2a557d..c1bda409f4e 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, ExtensionsModel } from './extensionsModel'; -import { InstallAction, UninstallAction } from './extensionsActions'; +import { CombinedInstallAction } from './extensionsActions'; export interface ITemplateData { extension: IExtension; @@ -89,13 +89,9 @@ export class Renderer implements IPagedRenderer { data.description.textContent = extension.description; data.actionbar.clear(); - const installAction = new InstallAction(this.model, extension); + const installAction = new CombinedInstallAction(this.model, extension); data.actionbar.push(installAction, actionOptions); data.disposables.push(installAction); - - const uninstallAction = new UninstallAction(this.model, extension); - data.actionbar.push(uninstallAction, actionOptions); - data.disposables.push(uninstallAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 5ca24b953cc..04a7dc0fcec 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -122,8 +122,7 @@ export class ExtensionsModel { const installedById = index(this.installed, e => e.local.id); this.installed = result.map(local => { - const id = local.path; - const extension = installedById[id] || new Extension(this.stateProvider, local); + const extension = installedById[local.id] || new Extension(this.stateProvider, local); extension.local = local; return extension; }); @@ -241,11 +240,11 @@ export class ExtensionsModel { } private getExtensionState(extension: Extension): ExtensionState { - if (this.installed.indexOf(extension) > -1) { + if (this.installed.some(e => e === extension || (e.gallery && extension.gallery && e.gallery.id === extension.gallery.id))) { return ExtensionState.Installed; } - if (this.installing.some(e => e.extension === extension)) { + if (extension.gallery && this.installing.some(e => e.extension.gallery.id === extension.gallery.id)) { return ExtensionState.Installing; } From d0dc1bdd66cc07415306019810e1914ee39cd408 Mon Sep 17 00:00:00 2001 From: Erich Gamma Date: Mon, 20 Jun 2016 15:06:04 +0200 Subject: [PATCH 073/126] fix for #7882 --- .../parts/emmet/node/emmetActions.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/emmet/node/emmetActions.ts b/src/vs/workbench/parts/emmet/node/emmetActions.ts index 0b066b726a5..358ae220ebd 100644 --- a/src/vs/workbench/parts/emmet/node/emmetActions.ts +++ b/src/vs/workbench/parts/emmet/node/emmetActions.ts @@ -15,13 +15,11 @@ import nls = require('vs/nls'); export abstract class EmmetEditorAction extends EditorAction { - protected static editorAccessor: EditorAccessor; + protected editorAccessor: EditorAccessor; constructor(descriptor: IEditorActionDescriptorData, editor: ICommonCodeEditor) { super(descriptor, editor, Behaviour.TextFocus); - if (!EmmetEditorAction.editorAccessor) { - EmmetEditorAction.editorAccessor = new EditorAccessor(editor); - } + this.editorAccessor = new EditorAccessor(editor); } abstract runEmmetAction(_module: any); @@ -30,15 +28,15 @@ export abstract class EmmetEditorAction extends EditorAction { return new TPromise((c, e) => { require(['emmet'], (_module) => { try { - if (!EmmetEditorAction.editorAccessor.isEmmetEnabledMode()) { - EmmetEditorAction.editorAccessor.noExpansionOccurred(); + if (!this.editorAccessor.isEmmetEnabledMode()) { + this.editorAccessor.noExpansionOccurred(); return; } this.runEmmetAction(_module); } catch (err) { // } finally { - EmmetEditorAction.editorAccessor.flushCache(); + this.editorAccessor.flushCache(); } }, e); }); @@ -53,8 +51,8 @@ export class ExpandAbbreviationAction extends EmmetEditorAction { } public runEmmetAction(_module) { - if (!_module.run('expand_abbreviation', EmmetEditorAction.editorAccessor)) { - EmmetEditorAction.editorAccessor.noExpansionOccurred(); + if (!_module.run('expand_abbreviation', this.editorAccessor)) { + this.editorAccessor.noExpansionOccurred(); } } } @@ -67,8 +65,8 @@ export class RemoveTagAction extends EmmetEditorAction { } public runEmmetAction(_module) { - if (!_module.run('remove_tag', EmmetEditorAction.editorAccessor)) { - EmmetEditorAction.editorAccessor.noExpansionOccurred(); + if (!_module.run('remove_tag', this.editorAccessor)) { + this.editorAccessor.noExpansionOccurred(); } } } @@ -91,8 +89,8 @@ export class UpdateTagAction extends EmmetEditorAction { } private wrapAbbreviation(_module: any, tag) { - if (!_module.run('update_tag', EmmetEditorAction.editorAccessor, tag)) { - EmmetEditorAction.editorAccessor.noExpansionOccurred(); + if (!_module.run('update_tag', this.editorAccessor, tag)) { + this.editorAccessor.noExpansionOccurred(); } } } @@ -115,8 +113,8 @@ export class WrapWithAbbreviationAction extends EmmetEditorAction { } private wrapAbbreviation(_module: any, abbreviation) { - if (!_module.run('wrap_with_abbreviation', EmmetEditorAction.editorAccessor, abbreviation)) { - EmmetEditorAction.editorAccessor.noExpansionOccurred(); + if (!_module.run('wrap_with_abbreviation', this.editorAccessor, abbreviation)) { + this.editorAccessor.noExpansionOccurred(); } } } \ No newline at end of file From c6828537f596998f89dc56f18922a30069fbbb9c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 15:13:53 +0200 Subject: [PATCH 074/126] extensions: keyboard navigation --- src/vs/base/browser/ui/list/list.css | 10 ++++---- src/vs/base/browser/ui/list/listPaging.ts | 24 +++++++++++++++++++ src/vs/base/browser/ui/list/listWidget.ts | 16 +++++++++---- .../contrib/suggest/browser/suggestWidget.ts | 10 ++++---- .../electron-browser/extensionsViewlet.ts | 17 ++++++++++--- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css index 64bbf7167c6..a10b9a83103 100644 --- a/src/vs/base/browser/ui/list/list.css +++ b/src/vs/base/browser/ui/list/list.css @@ -47,12 +47,12 @@ .vs-dark .monaco-list-row:hover { background-color: rgba(255, 255, 255, 0.08); } .hc-black .monaco-list-row:hover { outline: 1px dashed #f38518; background: transparent; } -/* Selection */ -.monaco-list-row.selected { background-color: #4FA7FF; color: white; } -.vs-dark .monaco-list-row.selected { background-color: #0E639C; color: white; } -.hc-black .monaco-list-row.selected { border: 1px solid #f38518; } - /* Focus */ .monaco-list-row.focused { background-color: #DCEBFC; } .vs-dark .monaco-list-row.focused { background-color: #073655; } .hc-black .monaco-list-row.focused { outline: 1px dotted #f38518; background: transparent } + +/* Selection */ +.monaco-list-row.selected { background-color: #4FA7FF; color: white; } +.vs-dark .monaco-list-row.selected { background-color: #0E639C; color: white; } +.hc-black .monaco-list-row.selected { border: 1px solid #f38518; } diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 0676a9e3ab2..d80880b8d49 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -93,6 +93,30 @@ export class PagedList { return this.list.scrollTop; } + focusNext(n?: number, loop?: boolean): void { + this.list.focusNext(n, loop); + } + + focusPrevious(n?: number, loop?: boolean): void { + this.list.focusPrevious(n, loop); + } + + selectNext(n?: number, loop?: boolean): void { + this.list.selectNext(n, loop); + } + + selectPrevious(n?: number, loop?: boolean): void { + this.list.selectPrevious(n, loop); + } + + getFocus(): number[] { + return this.list.getFocus(); + } + + setSelection(...indexes: number[]): void { + this.list.setSelection(...indexes); + } + layout(height?: number): void { this.list.layout(height); } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 4dfb48f44b2..83a31054150 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -239,6 +239,10 @@ export class List implements IDisposable { this.setSelection(Math.max(index, 0)); } + getSelection(): number[] { + return this.selection.get(); + } + setFocus(...indexes: number[]): void { this.eventBufferer.bufferEvents(() => { indexes = indexes.concat(this.focus.set(...indexes)); @@ -265,7 +269,7 @@ export class List implements IDisposable { let lastPageIndex = this.view.indexAt(this.view.getScrollTop() + this.view.renderHeight); lastPageIndex = lastPageIndex === 0 ? 0 : lastPageIndex - 1; const lastPageElement = this.view.element(lastPageIndex); - const currentlyFocusedElement = this.getFocus()[0]; + const currentlyFocusedElement = this.getFocusedElements()[0]; if (currentlyFocusedElement !== lastPageElement) { this.setFocus(lastPageIndex); @@ -291,7 +295,7 @@ export class List implements IDisposable { } const firstPageElement = this.view.element(firstPageIndex); - const currentlyFocusedElement = this.getFocus()[0]; + const currentlyFocusedElement = this.getFocusedElements()[0]; if (currentlyFocusedElement !== firstPageElement) { this.setFocus(firstPageIndex); @@ -306,8 +310,12 @@ export class List implements IDisposable { } } - getFocus(): T[] { - return this.focus.get().map(i => this.view.element(i)); + getFocus(): number[] { + return this.focus.get(); + } + + getFocusedElements(): T[] { + return this.getFocus().map(i => this.view.element(i)); } reveal(index: number, relativeTop?: number): void { diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index a4ec74e26b9..56481279c39 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -143,7 +143,7 @@ class Delegate implements IDelegate { constructor(private listProvider: () => List) { } getHeight(element: CompletionItem): number { - const focus = this.listProvider().getFocus()[0]; + const focus = this.listProvider().getFocusedElements()[0]; if (element.suggestion.documentationLabel && element === focus) { return FocusHeight; @@ -735,7 +735,7 @@ export class SuggestWidget implements IContentWidget, IDisposable { case State.Loading: return !this.isAuto; default: - const focus = this.list.getFocus()[0]; + const focus = this.list.getFocusedElements()[0]; if (focus) { this.list.setSelection(this.completionModel.items.indexOf(focus)); } else { @@ -756,7 +756,7 @@ export class SuggestWidget implements IContentWidget, IDisposable { return; } - const item = this.list.getFocus()[0]; + const item = this.list.getFocusedElements()[0]; if (!item || !item.suggestion.documentationLabel) { return; @@ -820,7 +820,7 @@ export class SuggestWidget implements IContentWidget, IDisposable { } else if (this.state === State.Details) { height = 12 * UnfocusedHeight; } else { - const focus = this.list.getFocus()[0]; + const focus = this.list.getFocusedElements()[0]; const focusHeight = focus ? this.delegate.getHeight(focus) : UnfocusedHeight; height = focusHeight; @@ -839,7 +839,7 @@ export class SuggestWidget implements IContentWidget, IDisposable { if (this.state !== State.Details) { this.details.render(null); } else { - this.details.render(this.list.getFocus()[0]); + this.details.render(this.list.getFocusedElements()[0]); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 0979f9c3dc2..23c95824ace 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -124,9 +124,20 @@ export class ExtensionsViewlet extends Viewlet { } private onSearchKeyDown(e: StandardKeyboardEvent): void { - if (e.keyCode === KeyCode.Escape) { - this.searchBox.value = ''; - this.triggerSearch(0); + switch (e.keyCode) { + case KeyCode.DownArrow: + this.list.focusNext(); + break; + case KeyCode.UpArrow: + this.list.focusPrevious(); + break; + case KeyCode.Enter: + this.list.setSelection(...this.list.getFocus()); + break; + case KeyCode.Escape: + this.searchBox.value = ''; + this.triggerSearch(0); + break; } } From b09cdc7e7c638b17ada05cabcd38a840f01e8fb9 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 15:17:28 +0200 Subject: [PATCH 075/126] what --- .../extensionManagement/node/extensionManagementService.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 36776a03836..3ce7c7494ec 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -182,10 +182,6 @@ export class ExtensionManagementService implements IExtensionManagementService { return version; }); } - id: string; - manifest: IExtensionManifest; - metadata: IGalleryMetadata; - path: string; private installValidExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { const extensionPath = path.join(this.extensionsPath, id); From da501b031fbadb68d497821237657ad4aa978e48 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Mon, 20 Jun 2016 15:20:30 +0200 Subject: [PATCH 076/126] update node-debug (add variable value support) --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 01d228a4a17..3be7e95786b 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "f9803b8/node-debug.zip", + "zip": "babb057/node-debug.zip", "output": "" } From 8550d8f290a995b807d216f6fb1b851efaa157ac Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 15:24:39 +0200 Subject: [PATCH 077/126] extension actions: more fixes --- .../extensions/electron-browser/extensionsActions.ts | 4 ++++ .../parts/extensions/electron-browser/extensionsModel.ts | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 4948560ebb1..1b753d9f91c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -269,6 +269,10 @@ export class CombinedInstallAction extends Action { this.enabled = true; this.label = this.uninstallAction.label; this.class = this.uninstallAction.class; + } else if (this.extension.state === ExtensionState.Installing) { + this.enabled = false; + this.label = this.installAction.label; + this.class = this.installAction.class; } else { this.enabled = false; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 04a7dc0fcec..b0286640469 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -127,7 +127,11 @@ export class ExtensionsModel { return extension; }); - return this.installed; + const installing = this.installing + .filter(e => !this.installed.some(installed => installed.local.id === e.id)) + .map(e => e.extension); + + return [...this.installed, ...installing]; }); } @@ -178,7 +182,7 @@ export class ExtensionsModel { } const ext = extension as Extension; - const local = ext.local; + const local = ext.local || this.installed.filter(e => e.local.metadata && ext.gallery && e.local.metadata.id === ext.gallery.id)[0].local; if (!local) { return TPromise.wrapError(new Error('Missing local')); From d2f9b29ca3b39bf7a5cac40a54c7a606fc48c216 Mon Sep 17 00:00:00 2001 From: Erich Gamma Date: Mon, 20 Jun 2016 15:51:58 +0200 Subject: [PATCH 078/126] Update TypeScript dependency to ^1.8.10 (1.8.0 produces errors). --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9dd9d64c2d1..bf7459e2962 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "sinon": "^1.17.2", "source-map": "^0.4.4", "tslint": "^3.3.0", - "typescript": "^1.8.0", + "typescript": "^1.8.10", "uglify-js": "2.4.8", "underscore": "^1.8.2", "vinyl": "^0.4.5", From 3daeb0fca83edfe1753bcc54b38e61eda4677d71 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 15:56:24 +0200 Subject: [PATCH 079/126] event: dom events --- src/vs/base/browser/event.ts | 127 +++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/vs/base/browser/event.ts diff --git a/src/vs/base/browser/event.ts b/src/vs/base/browser/event.ts new file mode 100644 index 00000000000..34c37b47102 --- /dev/null +++ b/src/vs/base/browser/event.ts @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------------------------- + * 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 _Event, { Emitter } from 'vs/base/common/event'; + +export interface IDomEvent { + (element: HTMLElement, type: "MSContentZoom", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureChange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureDoubleTap", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureEnd", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureHold", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureStart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGestureTap", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSGotPointerCapture", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSInertiaStart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSLostPointerCapture", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSManipulationStateChanged", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerCancel", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerDown", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerEnter", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerLeave", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerMove", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerOut", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerOver", useCapture?: boolean): _Event; + (element: HTMLElement, type: "MSPointerUp", useCapture?: boolean): _Event; + (element: HTMLElement, type: "abort", useCapture?: boolean): _Event; + (element: HTMLElement, type: "activate", useCapture?: boolean): _Event; + (element: HTMLElement, type: "ariarequest", useCapture?: boolean): _Event; + (element: HTMLElement, type: "beforeactivate", useCapture?: boolean): _Event; + (element: HTMLElement, type: "beforecopy", useCapture?: boolean): _Event; + (element: HTMLElement, type: "beforecut", useCapture?: boolean): _Event; + (element: HTMLElement, type: "beforedeactivate", useCapture?: boolean): _Event; + (element: HTMLElement, type: "beforepaste", useCapture?: boolean): _Event; + (element: HTMLElement, type: "blur", useCapture?: boolean): _Event; + (element: HTMLElement, type: "canplay", useCapture?: boolean): _Event; + (element: HTMLElement, type: "canplaythrough", useCapture?: boolean): _Event; + (element: HTMLElement, type: "change", useCapture?: boolean): _Event; + (element: HTMLElement, type: "click", useCapture?: boolean): _Event; + (element: HTMLElement, type: "command", useCapture?: boolean): _Event; + (element: HTMLElement, type: "contextmenu", useCapture?: boolean): _Event; + (element: HTMLElement, type: "copy", useCapture?: boolean): _Event; + (element: HTMLElement, type: "cuechange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "cut", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dblclick", useCapture?: boolean): _Event; + (element: HTMLElement, type: "deactivate", useCapture?: boolean): _Event; + (element: HTMLElement, type: "drag", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dragend", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dragenter", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dragleave", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dragover", useCapture?: boolean): _Event; + (element: HTMLElement, type: "dragstart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "drop", useCapture?: boolean): _Event; + (element: HTMLElement, type: "durationchange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "emptied", useCapture?: boolean): _Event; + (element: HTMLElement, type: "ended", useCapture?: boolean): _Event; + (element: HTMLElement, type: "error", useCapture?: boolean): _Event; + (element: HTMLElement, type: "focus", useCapture?: boolean): _Event; + (element: HTMLElement, type: "gotpointercapture", useCapture?: boolean): _Event; + (element: HTMLElement, type: "input", useCapture?: boolean): _Event; + (element: HTMLElement, type: "keydown", useCapture?: boolean): _Event; + (element: HTMLElement, type: "keypress", useCapture?: boolean): _Event; + (element: HTMLElement, type: "keyup", useCapture?: boolean): _Event; + (element: HTMLElement, type: "load", useCapture?: boolean): _Event; + (element: HTMLElement, type: "loadeddata", useCapture?: boolean): _Event; + (element: HTMLElement, type: "loadedmetadata", useCapture?: boolean): _Event; + (element: HTMLElement, type: "loadstart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "lostpointercapture", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mousedown", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mouseenter", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mouseleave", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mousemove", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mouseout", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mouseover", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mouseup", useCapture?: boolean): _Event; + (element: HTMLElement, type: "mousewheel", useCapture?: boolean): _Event; + (element: HTMLElement, type: "paste", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pause", useCapture?: boolean): _Event; + (element: HTMLElement, type: "play", useCapture?: boolean): _Event; + (element: HTMLElement, type: "playing", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointercancel", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerdown", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerenter", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerleave", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointermove", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerout", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerover", useCapture?: boolean): _Event; + (element: HTMLElement, type: "pointerup", useCapture?: boolean): _Event; + (element: HTMLElement, type: "progress", useCapture?: boolean): _Event; + (element: HTMLElement, type: "ratechange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "reset", useCapture?: boolean): _Event; + (element: HTMLElement, type: "scroll", useCapture?: boolean): _Event; + (element: HTMLElement, type: "seeked", useCapture?: boolean): _Event; + (element: HTMLElement, type: "seeking", useCapture?: boolean): _Event; + (element: HTMLElement, type: "select", useCapture?: boolean): _Event; + (element: HTMLElement, type: "selectstart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "stalled", useCapture?: boolean): _Event; + (element: HTMLElement, type: "submit", useCapture?: boolean): _Event; + (element: HTMLElement, type: "suspend", useCapture?: boolean): _Event; + (element: HTMLElement, type: "timeupdate", useCapture?: boolean): _Event; + (element: HTMLElement, type: "touchcancel", useCapture?: boolean): _Event; + (element: HTMLElement, type: "touchend", useCapture?: boolean): _Event; + (element: HTMLElement, type: "touchmove", useCapture?: boolean): _Event; + (element: HTMLElement, type: "touchstart", useCapture?: boolean): _Event; + (element: HTMLElement, type: "volumechange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "waiting", useCapture?: boolean): _Event; + (element: HTMLElement, type: "webkitfullscreenchange", useCapture?: boolean): _Event; + (element: HTMLElement, type: "webkitfullscreenerror", useCapture?: boolean): _Event; + (element: HTMLElement, type: "wheel", useCapture?: boolean): _Event; + (element: HTMLElement, type: string, useCapture?: boolean): _Event; +} + +export const domEvent: IDomEvent = (element: HTMLElement, type: string, useCapture?) => { + const fn = e => emitter.fire(e); + const emitter = new Emitter({ + onFirstListenerAdd: () => { + element.addEventListener(type, fn); + }, + onLastListenerRemove: () => { + element.removeEventListener(type, fn); + } + }); + + return emitter.event; +}; From 512ac4dc41a6d61993aa8c6dfa9fcd3ea4883907 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 16:04:30 +0200 Subject: [PATCH 080/126] filterEvent --- src/vs/base/common/event.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index c6dee602171..fc550668b0a 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -152,8 +152,11 @@ export function fromEventEmitter(emitter: EventEmitter, eventType: string): E } export function mapEvent(event: Event, map: (i:I)=>O): Event { - return (listener, thisArgs?, disposables?) => - event(i => listener(map(i)), thisArgs, disposables); + return (listener, thisArgs?, disposables?) => event(i => listener(map(i)), thisArgs, disposables); +} + +export function filterEvent(event: Event, filter: (e:T)=>boolean): Event { + return (listener, thisArgs?, disposables?) => event(e => filter(e) && listener(e), thisArgs, disposables); } enum EventDelayerState { From c9a739067cebb3e31fc0098a6a564b0cb6a8f575 Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Mon, 20 Jun 2016 17:10:56 +0300 Subject: [PATCH 081/126] Added support Emmet for Sass and Stylus (#7887) --- src/vs/workbench/parts/emmet/node/editorAccessor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/emmet/node/editorAccessor.ts b/src/vs/workbench/parts/emmet/node/editorAccessor.ts index 81a3a40c16a..1e2abb9d378 100644 --- a/src/vs/workbench/parts/emmet/node/editorAccessor.ts +++ b/src/vs/workbench/parts/emmet/node/editorAccessor.ts @@ -19,7 +19,7 @@ export class EditorAccessor implements emmet.Editor { lineStarts: number[] = null; - emmetSupportedModes = ['html', 'razor', 'css', 'less', 'scss', 'xml', 'xsl', 'jade', 'handlebars', 'ejs', 'hbs', 'jsx', 'tsx', 'erb', 'php', 'twig']; + emmetSupportedModes = ['html', 'razor', 'css', 'less', 'sass', 'scss', 'stylus', 'xml', 'xsl', 'jade', 'handlebars', 'ejs', 'hbs', 'jsx', 'tsx', 'erb', 'php', 'twig']; constructor(editor: ICommonCodeEditor) { this.editor = editor; @@ -121,8 +121,8 @@ export class EditorAccessor implements emmet.Editor { if (/\b(typescriptreact|javascriptreact)\b/.test(syntax)) { // treat like tsx like jsx return 'jsx'; } - if (syntax === 'stylus') { // map stylus to css - return 'css'; + if (syntax === 'sass-indented') { // map sass-indented to sass + return 'sass'; } return syntax; } From 730ed553d919a2243e9f3b89b9d1a28eb9fd8f81 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 16:13:01 +0200 Subject: [PATCH 082/126] list: focus --- src/vs/base/browser/ui/list/listView.ts | 1 - src/vs/base/browser/ui/list/listWidget.ts | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index cf0b8fc2b91..988684bfa38 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -78,7 +78,6 @@ export class ListView implements IDisposable { this._domNode = document.createElement('div'); this._domNode.className = 'monaco-list'; - this._domNode.tabIndex = 0; this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 83a31054150..cba1e19027a 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -8,6 +8,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isNumber } from 'vs/base/common/types'; import * as DOM from 'vs/base/browser/dom'; import Event, { Emitter, mapEvent, EventBufferer } from 'vs/base/common/event'; +import { domEvent } from 'vs/base/browser/event'; import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list'; import { ListView, IListViewOptions } from './listView'; @@ -138,6 +139,8 @@ class Controller implements IDisposable { private onClick(e: IListMouseEvent) { e.preventDefault(); e.stopPropagation(); + this.view.domNode.focus(); + this.list.setFocus(e.index); this.list.setSelection(e.index); } @@ -170,6 +173,9 @@ export class List implements IDisposable { return this.eventBufferer.wrapEvent(mapEvent(this.selection.onChange, e => this.toListEvent(e))); } + private _onDOMFocus: Event; + get onDOMFocus(): Event { return this._onDOMFocus; } + constructor( container: HTMLElement, delegate: IDelegate, @@ -188,7 +194,10 @@ export class List implements IDisposable { this.view = new ListView(container, delegate, renderers, options); this.view.domNode.setAttribute('role', 'listbox'); + this.view.domNode.tabIndex = 0; this.controller = new Controller(this, this.view); + + this._onDOMFocus = domEvent(this.view.domNode, 'focus'); } splice(start: number, deleteCount: number, ...elements: T[]): void { From 479303a8dade73198fb03f229491f506bb14fbed Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 16:13:10 +0200 Subject: [PATCH 083/126] extensions viewlet: ux --- src/vs/base/browser/ui/list/listPaging.ts | 1 + .../electron-browser/extensionsViewlet.ts | 51 ++++++++++++------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index d80880b8d49..7da5370aec3 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -62,6 +62,7 @@ export class PagedList { private list: List; private _model: PagedModel; + get onDOMFocus(): Event { return this.list.onDOMFocus; } constructor( container: HTMLElement, diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 23c95824ace..91492dba36a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -11,6 +11,8 @@ import { ThrottledDelayer, always } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; +import { mapEvent, filterEvent } from 'vs/base/common/event'; +import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { Viewlet } from 'vs/workbench/browser/viewlet'; @@ -66,8 +68,22 @@ export class ExtensionsViewlet extends Viewlet { const renderer = this.instantiationService.createInstance(Renderer, this.model); this.list = new PagedList(this.extensionsBox, delegate, [renderer]); - this.searchBox.onkeydown = e => this.onSearchKeyDown(new StandardKeyboardEvent(e)); - this.searchBox.oninput = () => this.triggerSearch(); + const onRawKeyDown = domEvent(this.searchBox, 'keydown'); + const onKeyDown = mapEvent(onRawKeyDown, e => new StandardKeyboardEvent(e)); + const onEnter = filterEvent(onKeyDown, e => e.keyCode === KeyCode.Enter); + const onEscape = filterEvent(onKeyDown, e => e.keyCode === KeyCode.Escape); + const onUpArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.UpArrow); + const onDownArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.DownArrow); + + onEnter(() => this.onEnter(), null, this.disposables); + onEscape(() => this.onEscape(), null, this.disposables); + onUpArrow(() => this.onUpArrow(), null, this.disposables); + onDownArrow(() => this.onDownArrow(), null, this.disposables); + + const onInput = domEvent(this.searchBox, 'input'); + onInput(() => this.triggerSearch(), null, this.disposables); + + this.list.onDOMFocus(() => this.searchBox.focus(), null, this.disposables); this.list.onSelectionChange(e => { const [extension] = e.elements; @@ -123,22 +139,21 @@ export class ExtensionsViewlet extends Viewlet { .then(model => this.list.model = model); } - private onSearchKeyDown(e: StandardKeyboardEvent): void { - switch (e.keyCode) { - case KeyCode.DownArrow: - this.list.focusNext(); - break; - case KeyCode.UpArrow: - this.list.focusPrevious(); - break; - case KeyCode.Enter: - this.list.setSelection(...this.list.getFocus()); - break; - case KeyCode.Escape: - this.searchBox.value = ''; - this.triggerSearch(0); - break; - } + private onEnter(): void { + this.list.setSelection(...this.list.getFocus()); + } + + private onEscape(): void { + this.searchBox.value = ''; + this.triggerSearch(0); + } + + private onUpArrow(): void { + this.list.focusPrevious(); + } + + private onDownArrow(): void { + this.list.focusNext(); } dispose(): void { From d3893e9467e2d0430e1d16523545b358075b7ed6 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 16:52:40 +0200 Subject: [PATCH 084/126] extension.readmeUrl --- .../common/extensionManagement.ts | 1 + .../node/extensionManagementService.ts | 27 ++++++++++++------- .../electron-browser/extensionsModel.ts | 13 +++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 6d9779b2f0a..4e34fef5d12 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -60,6 +60,7 @@ export interface ILocalExtension { manifest: IExtensionManifest; metadata: IGalleryMetadata; path: string; + readmeUrl: string; } export const IExtensionManagementService = createDecorator('extensionManagementService'); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 3ce7c7494ec..c784b141ac3 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -191,11 +191,16 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => pfs.readFile(manifestPath, 'utf8')) .then(raw => parseManifest(raw)) .then(({ manifest }) => { - const local: ILocalExtension = { id, manifest, metadata, path: extensionPath }; - const rawManifest = assign(manifest, { __metadata: metadata }); + return pfs.readdir(extensionPath).then(children => { + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const readmeUrl = readme ? `file://${ extensionPath }/${ readme }` : null; - return pfs.writeFile(manifestPath, JSON.stringify(rawManifest, null, '\t')) - .then(() => this._onDidInstallExtension.fire({ id, local })); + const local: ILocalExtension = { id, manifest, metadata, path: extensionPath, readmeUrl }; + const rawManifest = assign(manifest, { __metadata: metadata }); + + return pfs.writeFile(manifestPath, JSON.stringify(rawManifest, null, '\t')) + .then(() => this._onDidInstallExtension.fire({ id, local })); + }); }) .then(null, error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); }); } @@ -236,12 +241,16 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(extensionIds => Promise.join(extensionIds.map(id => { const extensionPath = path.join(this.extensionsPath, id); - return limiter.queue( - () => pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') + const each = () => pfs.readdir(extensionPath).then(children => { + const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0]; + const readmeUrl = readme ? `file://${ extensionPath }/${ readme }` : null; + + return pfs.readFile(path.join(extensionPath, 'package.json'), 'utf8') .then(raw => parseManifest(raw)) - .then(({ manifest, metadata }) => ({ id, manifest, metadata, path: extensionPath })) - .then(null, () => null) - ); + .then(({ manifest, metadata }) => ({ id, manifest, metadata, path: extensionPath, readmeUrl })); + }).then(null, () => null); + + return limiter.queue(each); }))) .then(result => result.filter(a => !!a)); }); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index b0286640469..bdd8825c3aa 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -28,6 +28,7 @@ export interface IExtension { publisherDisplayName: string; version: string; description: string; + readmeUrl: string; iconUrl: string; } @@ -79,6 +80,18 @@ class Extension implements IExtension { return this.local ? this.local.manifest.description : this.gallery.description; } + get readmeUrl(): string { + if (this.local && this.local.readmeUrl) { + return this.local.readmeUrl; + } + + if (this.gallery && this.gallery.versions[0].readmeUrl) { + return this.gallery.versions[0].readmeUrl; + } + + return null; + } + get iconUrl(): string { if (this.local && this.local.manifest.icon) { return `file://${ this.local.path }/${ this.local.manifest.icon }`; From 56593a734b76c91265ea1886d0a40b0b54de34c8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 16:54:05 +0200 Subject: [PATCH 085/126] show readme --- .../electron-browser/extensionEditor.ts | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index aa0f98a87f7..fbf9f959e98 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -8,19 +8,17 @@ import 'vs/css!./media/extensionEditor'; import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; -import { assign } from 'vs/base/common/objects'; import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IRequestService } from 'vs/platform/request/common/request'; // import { IExtension } from './extensionsModel'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; -import { text as downloadText, IRequestOptions } from 'vs/base/node/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { getProxyAgent } from 'vs/base/node/proxy'; import { ITemplateData } from './extensionsList'; import { EditorOptions } from 'vs/workbench/common/editor'; @@ -40,7 +38,8 @@ export class ExtensionEditor extends BaseEditor { @ITelemetryService telemetryService: ITelemetryService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, @IConfigurationService private configurationService: IConfigurationService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IRequestService private requestService: IRequestService ) { super(ExtensionEditor.ID, telemetryService); this._highlight = null; @@ -63,21 +62,16 @@ export class ExtensionEditor extends BaseEditor { this.body.innerHTML = ''; let promise = TPromise.as(null); - // const extension = input.extension; - - if (1 === 1/*local.path*/) { - // TODO@joao + const extension = input.extension; + if (!extension.readmeUrl) { + this.body.innerHTML = 'no readme :('; } else { - const version = null/*gallery.versions[0]*/; - const headers = version.downloadHeaders; - addClass(this.body, 'loading'); promise = super.setInput(input, options) - .then(() => this.request(version.readmeUrl)) - .then(opts => assign(opts, { headers })) - .then(opts => downloadText(opts)) + .then(() => this.requestService.makeRequest({ url: extension.readmeUrl })) + .then(response => response.responseText) .then(marked.parse) .then(html => { removeClass(this.body, 'loading'); @@ -94,17 +88,6 @@ export class ExtensionEditor extends BaseEditor { return; } - // Helper for proxy business... shameful. - // This should be pushed down and not rely on the configuration service - private request(url: string): IRequestOptions { - const http = this.configurationService.getConfiguration<{ proxy?: string; proxyStrictSSL?: boolean; }>('http'); - const proxyUrl: string = http.proxy; - const strictSSL: boolean = http.proxyStrictSSL; - const agent = getProxyAgent(url, { proxyUrl, strictSSL }); - - return { url, agent, strictSSL }; - } - dispose(): void { this._highlight = null; this.transientDisposables = dispose(this.transientDisposables); From eb41d47b260e75944e094ad481e9634431e04327 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 20 Jun 2016 17:36:41 +0200 Subject: [PATCH 086/126] delete markdown language from vscode --- build/gulpfile.vscode.js | 2 - src/vs/languages/buildfile.js | 3 - src/vs/languages/languages.main.ts | 1 - .../markdown/common/markdown.contribution.ts | 19 -- src/vs/languages/markdown/common/markdown.ts | 239 ------------------ .../markdown/test/common/markdown.test.ts | 116 --------- 6 files changed, 380 deletions(-) delete mode 100644 src/vs/languages/markdown/common/markdown.contribution.ts delete mode 100644 src/vs/languages/markdown/common/markdown.ts delete mode 100644 src/vs/languages/markdown/test/common/markdown.test.ts diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 4bdfd44987c..67fc67e9fa1 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -53,7 +53,6 @@ var vscodeResources = [ 'out-build/vs/base/worker/workerMainCompatibility.html', 'out-build/vs/base/worker/workerMain.{js,js.map}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', - 'out-build/vs/languages/markdown/common/*.css', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/electron-browser/index.html', 'out-build/vs/workbench/parts/debug/**/*.json', @@ -61,7 +60,6 @@ var vscodeResources = [ 'out-build/vs/workbench/parts/git/**/*.html', 'out-build/vs/workbench/parts/git/**/*.sh', 'out-build/vs/workbench/parts/html/browser/webview.html', - 'out-build/vs/workbench/parts/markdown/**/*.md', 'out-build/vs/workbench/parts/tasks/**/*.json', 'out-build/vs/workbench/parts/terminal/electron-browser/terminalProcess.js', 'out-build/vs/workbench/services/files/**/*.exe', diff --git a/src/vs/languages/buildfile.js b/src/vs/languages/buildfile.js index 8335e4d4fcb..965a3b68c9f 100644 --- a/src/vs/languages/buildfile.js +++ b/src/vs/languages/buildfile.js @@ -65,9 +65,6 @@ exports.collectModules = function(args) { .combine(worker) .define('vs/languages/html/common/htmlWorker', ['vs/languages/lib/common/beautify-html']); - // ---- markdown ------------------------------- - common.define('vs/languages/markdown/common/markdown', ['vs/languages/html/common/html']); - // ---- php ----------------------------------- common.define('vs/languages/php/common/php'); diff --git a/src/vs/languages/languages.main.ts b/src/vs/languages/languages.main.ts index 6b2325b0007..be15b628f86 100644 --- a/src/vs/languages/languages.main.ts +++ b/src/vs/languages/languages.main.ts @@ -8,5 +8,4 @@ import 'vs/languages/handlebars/common/handlebars.contribution'; import 'vs/languages/html/common/html.contribution'; -import 'vs/languages/markdown/common/markdown.contribution'; import 'vs/languages/razor/common/razor.contribution'; diff --git a/src/vs/languages/markdown/common/markdown.contribution.ts b/src/vs/languages/markdown/common/markdown.contribution.ts deleted file mode 100644 index a984f358078..00000000000 --- a/src/vs/languages/markdown/common/markdown.contribution.ts +++ /dev/null @@ -1,19 +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 {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -const register = false; -if (register) { - ModesRegistry.registerCompatMode({ - id: 'markdown', - extensions: ['.md', '.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mdtxt', '.mdtext'], - aliases: ['Markdown', 'markdown'], - mimetypes: ['text/x-web-markdown'], - moduleId: 'vs/languages/markdown/common/markdown', - ctorName: 'MarkdownMode' - }); -} \ No newline at end of file diff --git a/src/vs/languages/markdown/common/markdown.ts b/src/vs/languages/markdown/common/markdown.ts deleted file mode 100644 index ea7bbf1d308..00000000000 --- a/src/vs/languages/markdown/common/markdown.ts +++ /dev/null @@ -1,239 +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 Types = require('vs/editor/common/modes/monarch/monarchTypes'); -import Compile = require('vs/editor/common/modes/monarch/monarchCompile'); -import Modes = require('vs/editor/common/modes'); -import {htmlTokenTypes} from 'vs/languages/html/common/html'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IThreadService} from 'vs/platform/thread/common/thread'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {IEditorWorkerService} from 'vs/editor/common/services/editorWorkerService'; -import {AbstractMode} from 'vs/editor/common/modes/abstractMode'; -import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {wireCancellationToken} from 'vs/base/common/async'; - -export const TOKEN_HEADER_LEAD = 'entity.name.tag'; -export const TOKEN_HEADER = 'entity.name.tag'; -export const TOKEN_EXT_HEADER = 'entity.other.attribute-name'; -export const TOKEN_SEPARATOR = 'meta.separator'; -export const TOKEN_QUOTE = 'comment'; -export const TOKEN_LIST = 'keyword'; -export const TOKEN_BLOCK = 'string'; -export const TOKEN_BLOCK_CODE = 'variable.source'; - -export const language = - { - defaultToken: '', - tokenPostfix: '.md', - - // escape codes - control: /[\\`*_\[\]{}()#+\-\.!]/, - noncontrol: /[^\\`*_\[\]{}()#+\-\.!]/, - escapes: /\\(?:@control)/, - - // escape codes for javascript/CSS strings - jsescapes: /\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/, - - // non matched elements - empty: [ - 'area', 'base', 'basefont', 'br', 'col', 'frame', - 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param' - ], - - tokenizer: { - root: [ - - // headers (with #) - [/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/, ['white', TOKEN_HEADER_LEAD, TOKEN_HEADER, TOKEN_HEADER]], - - // headers (with =) - [/^\s*(=+|\-+)\s*$/, TOKEN_EXT_HEADER], - - // headers (with ***) - [/^\s*((\*[ ]?)+)\s*$/, TOKEN_SEPARATOR], - - // quote - [/^\s*>+/, TOKEN_QUOTE], - - // list (starting with * or number) - [/^\s*([\*\-+:]|\d+\.)\s/, TOKEN_LIST], - - // code block (4 spaces indent) - [/^(\t|[ ]{4})[^ ].*$/, TOKEN_BLOCK], - - // code block (3 tilde) - [/^\s*~{3}\s*((?:\w|[\/\-#])+)?\s*$/, { token: TOKEN_BLOCK, next: '@codeblock' }], - - // github style code blocks (with backticks and language) - [/^\s*```\s*((?:\w|[\/\-#])+)\s*$/, { token: TOKEN_BLOCK, next: '@codeblockgh', nextEmbedded: '$1' }], - - // github style code blocks (with backticks but no language) - [/^\s*`{3}\s*$/, { token: TOKEN_BLOCK, next: '@codeblock' }], - - // markup within lines - { include: '@linecontent' }, - ], - - codeblock: [ - [/^\s*~{3}\s*$/, { token: TOKEN_BLOCK, next: '@pop' }], - [/^\s*`{3}\s*$/, { token: TOKEN_BLOCK, next: '@pop' }], - [/.*$/, TOKEN_BLOCK_CODE], - ], - - // github style code blocks - codeblockgh: [ - [/```\s*$/, { token: '@rematch', switchTo: '@codeblockghend', nextEmbedded: '@pop' }], - [/[^`]*$/, TOKEN_BLOCK_CODE], - ], - - codeblockghend: [ - [/\s*```/, { token: TOKEN_BLOCK_CODE, next: '@pop' }], - [/./, '@rematch', '@pop'], - ], - - linecontent: [ - - // escapes - [/&\w+;/, 'string.escape'], - [/@escapes/, 'escape'], - - // various markup - [/\b__([^\\_]|@escapes|_(?!_))+__\b/, 'strong'], - [/\*\*([^\\*]|@escapes|\*(?!\*))+\*\*/, 'strong'], - [/\b_[^_]+_\b/, 'emphasis'], - [/\*([^\\*]|@escapes)+\*/, 'emphasis'], - [/`([^\\`]|@escapes)+`/, 'variable'], - - // links - [/\{[^}]+\}/, 'string.target'], - [/(!?\[)((?:[^\]\\]|@escapes)*)(\]\([^\)]+\))/, ['string.link', '', 'string.link']], - [/(!?\[)((?:[^\]\\]|@escapes)*)(\])/, 'string.link'], - - // or html - { include: 'html' }, - ], - - // Note: it is tempting to rather switch to the real HTML mode instead of building our own here - // but currently there is a limitation in Monarch that prevents us from doing it: The opening - // '<' would start the HTML mode, however there is no way to jump 1 character back to let the - // HTML mode also tokenize the opening angle bracket. Thus, even though we could jump to HTML, - // we cannot correctly tokenize it in that mode yet. - html: [ - // html tags - [/<(\w+)\/>/, htmlTokenTypes.getTag('$1')], - [/<(\w+)/, { - cases: { - '@empty': { token: htmlTokenTypes.getTag('$1'), next: '@tag.$1' }, - '@default': { token: htmlTokenTypes.getTag('$1'), bracket: '@open', next: '@tag.$1' } - } - }], - [/<\/(\w+)\s*>/, { token: htmlTokenTypes.getTag('$1'), bracket: '@close' }], - - [//, 'comment', '@pop'], - [/',] - }, - brackets: [['{', '}'], ['[', ']'], ['(', ')'], ['<', '>']], - autoClosingPairs: [] - }; - - public tokenizationSupport: Modes.ITokenizationSupport; - - constructor( - descriptor: Modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IThreadService threadService: IThreadService, - @IModeService modeService: IModeService, - @IEditorWorkerService editorWorkerService: IEditorWorkerService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(descriptor.id); - let lexer = Compile.compile(descriptor.id, language); - - this.tokenizationSupport = createTokenizationSupport(modeService, this, lexer); - - LanguageConfigurationRegistry.register(this.getId(), MarkdownMode.LANG_CONFIG); - - Modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: [], - shouldAutotriggerSuggest: false, - provideCompletionItems: (model, position, token) => { - return wireCancellationToken(token, editorWorkerService.textualSuggest(model.uri, position)); - } - }, true); - } -} \ No newline at end of file diff --git a/src/vs/languages/markdown/test/common/markdown.test.ts b/src/vs/languages/markdown/test/common/markdown.test.ts deleted file mode 100644 index e46e0d5b747..00000000000 --- a/src/vs/languages/markdown/test/common/markdown.test.ts +++ /dev/null @@ -1,116 +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 modesUtil = require('vs/editor/test/common/modesUtil'); -import Modes = require('vs/editor/common/modes'); -import {htmlTokenTypes} from 'vs/languages/html/common/html'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; -import {NULL_THREAD_SERVICE} from 'vs/platform/test/common/nullThreadService'; -import {IThreadService} from 'vs/platform/thread/common/thread'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; -import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; -import {MarkdownMode} from 'vs/languages/markdown/common/markdown'; -import {MockTokenizingMode} from 'vs/editor/test/common/mocks/mockMode'; - -class MarkdownMockModeService extends MockModeService { - isRegisteredMode(mimetypeOrModeId: string): boolean { - if (mimetypeOrModeId === 'javascript') { - return true; - } - if (mimetypeOrModeId === 'css') { - return true; - } - throw new Error('Not implemented'); - } - - getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Modes.IMode { - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'javascript') { - return new MockTokenizingMode('js', 'mock-js'); - } - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'css') { - return new MockTokenizingMode('css', 'mock-css'); - } - throw new Error('Not implemented'); - } - - getModeIdForLanguageName(alias:string): string { - if (alias === 'text/javascript') { - return 'javascript'; - } - if (alias === 'text/css') { - return 'css'; - } - console.log(alias); - throw new Error('Not implemented'); - } -} - -suite('Markdown - tokenization', () => { - - var tokenizationSupport: Modes.ITokenizationSupport; - - (function() { - let threadService = NULL_THREAD_SERVICE; - let modeService = new MarkdownMockModeService(); - let services = new ServiceCollection(); - services.set(IThreadService, threadService); - services.set(IModeService, modeService); - let inst = new InstantiationService(services); - threadService.setInstantiationService(inst); - - let mode = new MarkdownMode( - { id: 'markdown' }, - inst, - threadService, - modeService, - null, - null - ); - - tokenizationSupport = mode.tokenizationSupport; - - })(); - - test('', () => { - modesUtil.executeTests(tokenizationSupport, [ - // HTML and embedded content - bug 16912 - [{ - line: 'foo*bar*', - tokens: [ - { startIndex:0, type: htmlTokenTypes.getTag('b.md') }, - { startIndex:3, type: '' }, - { startIndex:6, type: htmlTokenTypes.getTag('b.md') }, - { startIndex:10, type: 'emphasis.md' } - ]}], - - [{ - line: '*bar*', - tokens: [ - { startIndex:0, type: htmlTokenTypes.getTag('b.md') }, - { startIndex:4, type: 'emphasis.md' } - ]}], - - [{ - line: '*bar*', - tokens: [ - { startIndex:0, type: htmlTokenTypes.getTag('script.md') }, - { startIndex:8, type: 'mock-js' }, - { startIndex:20, type: htmlTokenTypes.getTag('script.md') }, - { startIndex:29, type: 'emphasis.md' } - ]}], - - [{ - line: '*bar*', - tokens: [ - { startIndex:0, type: htmlTokenTypes.getTag('style.md') }, - { startIndex:7, type: 'mock-css' }, - { startIndex:30, type: htmlTokenTypes.getTag('style.md') }, - { startIndex:38, type: 'emphasis.md' } - ]}] - ]); - }); -}); From ad2d7155cd59a4b2ee50666292549ae078974040 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 20 Jun 2016 18:05:53 +0200 Subject: [PATCH 087/126] extension viewlet: images --- .../extensions/electron-browser/extensionEditor.ts | 9 ++++++++- .../extensions/electron-browser/extensionsList.ts | 8 ++++---- .../electron-browser/media/extensionEditor.css | 10 +++++++++- .../electron-browser/media/extensionsViewlet.css | 3 +++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index fbf9f959e98..4fdfedc8d95 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -26,6 +26,7 @@ export class ExtensionEditor extends BaseEditor { static ID: string = 'workbench.editor.extension'; + private icon: HTMLElement; private body: HTMLElement; private _highlight: ITemplateData; @@ -52,7 +53,11 @@ export class ExtensionEditor extends BaseEditor { const root = append(container, $('.extension-editor')); const header = append(root, $('.header')); - header.innerText = 'here goes description, author name, links, ratings, install buttons, etc'; + + this.icon = append(header, $('.icon')); + // const details = append(header, $('.details')); + + // header.innerText = 'here goes description, author name, links, ratings, install buttons, etc'; this.body = append(root, $('.body')); } @@ -64,6 +69,8 @@ export class ExtensionEditor extends BaseEditor { let promise = TPromise.as(null); const extension = input.extension; + this.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; + if (!extension.readmeUrl) { this.body.innerHTML = 'no readme :('; } else { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index c1bda409f4e..5ae9f3bf737 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -17,7 +17,7 @@ import { CombinedInstallAction } from './extensionsActions'; export interface ITemplateData { extension: IExtension; element: HTMLElement; - icon: HTMLImageElement; + icon: HTMLElement; name: HTMLElement; version: HTMLElement; author: HTMLElement; @@ -49,7 +49,7 @@ export class Renderer implements IPagedRenderer { renderTemplate(root: HTMLElement): ITemplateData { const element = append(root, $('.extension')); - const icon = append(element, $('img.icon')); + const icon = append(element, $('.icon')); const details = append(element, $('.details')); const header = append(details, $('.header')); const name = append(header, $('span.name.ellipsis')); @@ -69,7 +69,7 @@ export class Renderer implements IPagedRenderer { addClass(data.element, 'loading'); data.extension = null; - data.icon.src = ''; + data.icon.style.backgroundImage = ''; data.name.textContent = ''; data.version.textContent = ''; data.author.textContent = ''; @@ -82,7 +82,7 @@ export class Renderer implements IPagedRenderer { removeClass(data.element, 'loading'); data.extension = extension; - data.icon.src = extension.iconUrl; + data.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; data.name.textContent = extension.displayName; data.version.textContent = extension.version; data.author.textContent = extension.publisherDisplayName; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index b7d968f605f..3ca51d19158 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -12,11 +12,19 @@ } .extension-editor > .header { - height: 40px; + height: 128px; background: rgba(128, 128, 128, 0.15); /* TODO */ padding: 20px; } +.extension-editor > .header > .icon { + height: 128px; + width: 128px; + background-size: 128px; + background-repeat: no-repeat; + background-position: center center; +} + .extension-editor > .body { flex: 1; overflow-y: scroll; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index 9e118a0ebb9..b4c880b5eae 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -44,6 +44,9 @@ height: 42px; padding: 10px 14px 10px 0; flex-shrink: 0; + background-repeat: no-repeat; + background-size: 42px; + background-position: left center; } .extensions-viewlet > .extensions .extension.loading > .icon { From 62f0272219dc72fda5246d330640e6af52a10cd0 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 21 Jun 2016 00:33:12 +0200 Subject: [PATCH 088/126] update node-debug --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 3be7e95786b..81fcaee940f 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "babb057/node-debug.zip", + "zip": "1e5cde6/node-debug.zip", "output": "" } From d808ba31a697998f36c9c2cbdfc5f8d8e8b16ca2 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 21 Jun 2016 09:58:25 +0200 Subject: [PATCH 089/126] fix issue in restoring editors --- src/vs/workbench/browser/parts/editor/editorPart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 7b1d550a557..737653efed8 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -932,11 +932,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService // Validate width ratios const positions = rightEditors.length ? 3 : centerEditors.length ? 2 : 1; - if (widthRatios.length !== positions) { + if (!widthRatios || widthRatios.length !== positions) { if (!this.getVisibleEditors().length) { widthRatios = (positions === 3) ? [0.33, 0.33, 0.34] : (positions === 2) ? [0.5, 0.5] : [1]; } else { - widthRatios = void 0; // being taken care of by the layouting if editors are already open + widthRatios = void 0; } } From 4d2350a8250330ae6215f002200ae71efb0c8343 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 21 Jun 2016 10:54:53 +0200 Subject: [PATCH 090/126] Keybinding conflict (scrollPageDown, scrollPageUp) (fixes #7047) --- src/vs/editor/common/config/config.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/config/config.ts b/src/vs/editor/common/config/config.ts index 650fa4dfb6f..d4eee107698 100644 --- a/src/vs/editor/common/config/config.ts +++ b/src/vs/editor/common/config/config.ts @@ -231,10 +231,12 @@ registerCoreCommand(H.ScrollLineDown, { }); registerCoreCommand(H.ScrollPageUp, { - primary: KeyMod.CtrlCmd | KeyCode.PageUp + primary: KeyMod.CtrlCmd | KeyCode.PageUp, + win: { primary: KeyMod.Alt | KeyCode.PageUp } }); registerCoreCommand(H.ScrollPageDown, { - primary: KeyMod.CtrlCmd | KeyCode.PageDown + primary: KeyMod.CtrlCmd | KeyCode.PageDown, + win: { primary: KeyMod.Alt | KeyCode.PageDown } }); registerCoreCommand(H.CursorColumnSelectLeft, { From dd260e7fdd8a209398730c66d352d85185962fe3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 10:55:06 +0200 Subject: [PATCH 091/126] extension details --- .../electron-browser/extensionEditor.ts | 20 ++++++++++++++-- .../media/extensionEditor.css | 23 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 4fdfedc8d95..0b2e65d070a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -27,6 +27,11 @@ export class ExtensionEditor extends BaseEditor { static ID: string = 'workbench.editor.extension'; private icon: HTMLElement; + private name: HTMLElement; + private publisher: HTMLElement; + private installCount: HTMLElement; + private rating: HTMLElement; + private description: HTMLElement; private body: HTMLElement; private _highlight: ITemplateData; @@ -55,9 +60,17 @@ export class ExtensionEditor extends BaseEditor { const header = append(root, $('.header')); this.icon = append(header, $('.icon')); - // const details = append(header, $('.details')); - // header.innerText = 'here goes description, author name, links, ratings, install buttons, etc'; + const details = append(header, $('.details')); + this.name = append(details, $('.name')); + + const subtitle = append(details, $('.subtitle')); + this.publisher = append(subtitle, $('span.publisher')); + this.installCount = append(subtitle, $('span.install')); + this.rating = append(subtitle, $('span.rating')); + + this.description = append(details, $('p.description')); + this.body = append(root, $('.body')); } @@ -70,6 +83,9 @@ export class ExtensionEditor extends BaseEditor { const extension = input.extension; this.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; + this.name.textContent = extension.displayName; + this.publisher.textContent = extension.publisherDisplayName; + this.description.textContent = extension.description; if (!extension.readmeUrl) { this.body.innerHTML = 'no readme :('; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index 3ca51d19158..3f1c943c79f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -8,23 +8,42 @@ overflow-y: scroll; display: flex; flex-direction: column; - /*padding: 20px;*/ } .extension-editor > .header { + display: flex; height: 128px; - background: rgba(128, 128, 128, 0.15); /* TODO */ + background: rgba(128, 128, 128, 0.15); padding: 20px; + overflow: hidden; } .extension-editor > .header > .icon { height: 128px; width: 128px; + min-width: 128px; background-size: 128px; background-repeat: no-repeat; background-position: center center; } +.extension-editor > .header > .details { + flex: 1; + padding-left: 20px; + overflow: hidden; +} + +.extension-editor > .header > .details > .name { + font-size: 26px; + font-weight: 600; + line-height: normal; +} + +.extension-editor > .header > .details > .subtitle { + font-size: 18px; + padding-top: 10px; +} + .extension-editor > .body { flex: 1; overflow-y: scroll; From f555b323a4e6ff97c2e6007722de95f4bb3395c5 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 21 Jun 2016 11:34:56 +0200 Subject: [PATCH 092/126] debug: do not show 'canceled' error messages to the user fixes #7906 --- .../workbench/parts/debug/electron-browser/debugService.ts | 5 +++++ src/vs/workbench/parts/debug/node/v8Protocol.ts | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index ce69c5164c9..e7271fea91d 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -646,6 +646,11 @@ export class DebugService implements debug.IDebugService { isBuiltin: this.configurationManager.adapter.extensionDescription.isBuiltin }); }).then(undefined, (error: any) => { + if (error instanceof Error && error.message === 'Canceled') { + // Do not show 'canceled' error messages to the user #7906 + return TPromise.as(null); + } + this.telemetryService.publicLog('debugMisconfiguration', { type: configuration ? configuration.type : undefined }); this.setStateAndEmit(debug.State.Inactive); if (this.session) { diff --git a/src/vs/workbench/parts/debug/node/v8Protocol.ts b/src/vs/workbench/parts/debug/node/v8Protocol.ts index 340ec55ef33..e490d102c03 100644 --- a/src/vs/workbench/parts/debug/node/v8Protocol.ts +++ b/src/vs/workbench/parts/debug/node/v8Protocol.ts @@ -6,6 +6,7 @@ import stream = require('stream'); import uuid = require('vs/base/common/uuid'); import { TPromise } from 'vs/base/common/winjs.base'; +import { canceled } from 'vs/base/common/errors'; export abstract class V8Protocol { @@ -41,7 +42,9 @@ export abstract class V8Protocol { } protected send(command: string, args: any): TPromise { + let errorCallback; return new TPromise((completeDispatch, errorDispatch) => { + errorCallback = errorDispatch; this.doSend(command, args, (result: DebugProtocol.Response) => { if (result.success) { completeDispatch(result); @@ -49,7 +52,7 @@ export abstract class V8Protocol { errorDispatch(result); } }); - }); + }, () => errorCallback(canceled())); } private doSend(command: string, args: any, clb: (result: DebugProtocol.Response) => void): void { From ce48b74a5bee9b4a6976afe374401e7b9c7a661a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 21 Jun 2016 11:45:34 +0200 Subject: [PATCH 093/126] debug: move set / get expression value logic to super class fixes #7914 --- .../parts/debug/common/debugModel.ts | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index ae8095d401b..15b79893269 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -226,11 +226,12 @@ export class KeyValueOutputElement extends OutputElement { } } -export class ExpressionContainer implements debug.IExpressionContainer { +export abstract class ExpressionContainer implements debug.IExpressionContainer { private children: TPromise; public valueChanged: boolean; public static allValues: { [id: string]: string } = {}; + private _value: string; constructor(public reference: number, private id: string, private cacheChildren: boolean) { this.children = null; @@ -251,20 +252,6 @@ export class ExpressionContainer implements debug.IExpressionContainer { return this.id; } -} - -export class Expression extends ExpressionContainer implements debug.IExpression { - static DEFAULT_VALUE = 'not available'; - - public available: boolean; - private _value: string; - - constructor(public name: string, cacheChildren: boolean, id = uuid.generateUuid()) { - super(0, id, cacheChildren); - this.value = Expression.DEFAULT_VALUE; - this.available = false; - } - public get value(): string { return this._value; } @@ -277,15 +264,23 @@ export class Expression extends ExpressionContainer implements debug.IExpression } } -export class Variable extends ExpressionContainer implements debug.IExpression { +export class Expression extends ExpressionContainer implements debug.IExpression { + static DEFAULT_VALUE = 'not available'; - public value: string; + public available: boolean; + + constructor(public name: string, cacheChildren: boolean, id = uuid.generateUuid()) { + super(0, id, cacheChildren); + this.value = Expression.DEFAULT_VALUE; + this.available = false; + } +} + +export class Variable extends ExpressionContainer implements debug.IExpression { constructor(public parent: debug.IExpressionContainer, reference: number, public name: string, value: string, public available = true) { super(reference, `variable:${ parent.getId() }:${ name }`, true); this.value = massageValue(value); - this.valueChanged = ExpressionContainer.allValues[this.getId()] && ExpressionContainer.allValues[this.getId()] !== value; - ExpressionContainer.allValues[this.getId()] = value; } } From 82fea1b9c18c5f157a8536b7f901ee35422937bd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 21 Jun 2016 11:54:35 +0200 Subject: [PATCH 094/126] more explicit navigation in mru stack order --- .../quickopen/browser/quickOpenWidget.ts | 13 +++++-- .../base/parts/quickopen/common/quickOpen.ts | 5 +++ src/vs/code/electron-main/menus.ts | 4 +- .../parts/editor/editor.contribution.ts | 14 +++++-- .../browser/parts/editor/editorActions.ts | 39 +++++++++++++++++-- .../browser/parts/editor/editorPicker.ts | 13 +++++-- .../parts/quickopen/quickOpenController.ts | 6 +-- src/vs/workbench/browser/quickopen.ts | 4 +- 8 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 8c27201f26e..f8d94989037 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -575,12 +575,19 @@ export class QuickOpenWidget implements IModelProvider { } } - // Finally check for auto focus of second entry + // Check for auto focus of second entry else if (autoFocus.autoFocusSecondEntry) { if (entries.length > 1) { this.tree.focusNth(1); } } + + // Finally check for auto focus of last entry + else if (autoFocus.autoFocusLastEntry) { + if (entries.length > 1) { + this.tree.focusLast(); + } + } } public refresh(input: IModel, autoFocus: IAutoFocus): void { @@ -719,8 +726,8 @@ export class QuickOpenWidget implements IModelProvider { } } - public isQuickNavigating(): boolean { - return !!this.quickNavigateConfiguration; + public getQuickNavigateConfiguration(): IQuickNavigateConfiguration { + return this.quickNavigateConfiguration; } public setPlaceHolder(placeHolder: string): void { diff --git a/src/vs/base/parts/quickopen/common/quickOpen.ts b/src/vs/base/parts/quickopen/common/quickOpen.ts index bc2002d3609..8bbe2285f39 100644 --- a/src/vs/base/parts/quickopen/common/quickOpen.ts +++ b/src/vs/base/parts/quickopen/common/quickOpen.ts @@ -27,6 +27,11 @@ export interface IAutoFocus { */ autoFocusSecondEntry?: boolean; + /** + * If set to true, will automatically select the last entry from the result list. + */ + autoFocusLastEntry?: boolean; + /** * If set to true, will automatically select any entry whose label starts with the search * value. Since some entries to the top might match the query but not on the prefix, this diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index aaa18e0c357..6a29abf74bb 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -592,12 +592,14 @@ export class VSCodeMenu { let nextEditor = this.createMenuItem(nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor"), 'workbench.action.nextEditor'); let previousEditor = this.createMenuItem(nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor"), 'workbench.action.previousEditor'); - let previousEditorInGroup = this.createMenuItem(nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "Previous &&Editor in Group"), 'workbench.action.openPreviousEditorInGroup'); + let nextEditorInGroup = this.createMenuItem(nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group"), 'workbench.action.openNextRecentlyUsedEditorInGroup'); + let previousEditorInGroup = this.createMenuItem(nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group"), 'workbench.action.openPreviousRecentlyUsedEditorInGroup'); [ nextEditor, previousEditor, __separator__(), + nextEditorInGroup, previousEditorInGroup ].forEach(item => switchEditorMenu.append(item)); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 615198b418e..2ac7fa5f107 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -32,9 +32,9 @@ import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; import {EditorStacksModel} from 'vs/workbench/common/editor/editorStacksModel'; import {CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, OpenToSideAction, NavigateBetweenGroupsAction, FocusFirstGroupAction, FocusSecondGroupAction, FocusThirdGroupAction, EvenGroupWidthsAction, MaximizeGroupAction, MinimizeOtherGroupsAction, FocusPreviousGroup, FocusNextGroup, ShowEditorsInLeftGroupAction, - toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, ReopenClosedEditorAction, OpenPreviousEditorInGroupAction, NAVIGATE_IN_LEFT_GROUP_PREFIX, + toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_LEFT_GROUP_PREFIX, GlobalQuickOpenAction, OpenPreviousEditorFromHistoryAction, QuickOpenNavigateNextAction, QuickOpenNavigatePreviousAction, ShowAllEditorsAction, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, ClearEditorHistoryAction, ShowEditorsInCenterGroupAction, - NAVIGATE_IN_CENTER_GROUP_PREFIX, ShowEditorsInRightGroupAction, NAVIGATE_IN_RIGHT_GROUP_PREFIX, RemoveFromEditorHistoryAction, FocusLastEditorInStackAction + NAVIGATE_IN_CENTER_GROUP_PREFIX, ShowEditorsInRightGroupAction, NAVIGATE_IN_RIGHT_GROUP_PREFIX, RemoveFromEditorHistoryAction, FocusLastEditorInStackAction, OpenNextRecentlyUsedEditorInGroupAction } from 'vs/workbench/browser/parts/editor/editorActions'; // Register String Editor @@ -263,12 +263,18 @@ function navigateKeybinding(shift: boolean): IKeybindings { // Register Editor Actions const category = nls.localize('view', "View"); -registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditorInGroupAction, OpenPreviousEditorInGroupAction.ID, OpenPreviousEditorInGroupAction.LABEL, { +registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } -}), 'Open Previous in Editor Group'); +}), 'Open Next Recently Used Editor in Group'); +registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Shift |  KeyCode.Tab, + mac: { + primary: KeyMod.WinCtrl | KeyMod.Shift |  KeyCode.Tab + } +}), 'Open Previous Recently Used Editor in Group'); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllEditorsAction, ShowAllEditorsAction.ID, ShowAllEditorsAction.LABEL, { primary: null, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInLeftGroupAction, ShowEditorsInLeftGroupAction.ID, ShowEditorsInLeftGroupAction.LABEL), 'View: Show Editors in Left Group', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInCenterGroupAction, ShowEditorsInCenterGroupAction.ID, ShowEditorsInCenterGroupAction.LABEL), 'View: Show Editors in Center Group', category); diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 8ce3af32df8..1a588852832 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -1014,10 +1014,7 @@ export class ShowAllEditorsAction extends QuickOpenAction { } } -export class OpenPreviousEditorInGroupAction extends Action { - - public static ID = 'workbench.action.openPreviousEditorInGroup'; - public static LABEL = nls.localize('openPreviousEditorInGroup', "Open Previous in Editor Group"); +export class BaseQuickOpenEditorInGroupAction extends Action { constructor( id: string, @@ -1052,6 +1049,40 @@ export class OpenPreviousEditorInGroupAction extends Action { } } +export class OpenPreviousRecentlyUsedEditorInGroupAction extends BaseQuickOpenEditorInGroupAction { + + public static ID = 'workbench.action.openPreviousRecentlyUsedEditorInGroup'; + public static LABEL = nls.localize('openPreviousEditorInGroup', "Open Previous Recently Used Editor in Group"); + + constructor( + id: string, + label: string, + @IQuickOpenService quickOpenService: IQuickOpenService, + @IKeybindingService keybindingService: IKeybindingService, + @IEditorGroupService editorGroupService: IEditorGroupService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService + ) { + super(id, label, quickOpenService, keybindingService, editorGroupService, editorService); + } +} + +export class OpenNextRecentlyUsedEditorInGroupAction extends BaseQuickOpenEditorInGroupAction { + + public static ID = 'workbench.action.openNextRecentlyUsedEditorInGroup'; + public static LABEL = nls.localize('openNextEditorInGroup', "Open Next Recently Used Editor in Group"); + + constructor( + id: string, + label: string, + @IQuickOpenService quickOpenService: IQuickOpenService, + @IKeybindingService keybindingService: IKeybindingService, + @IEditorGroupService editorGroupService: IEditorGroupService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService + ) { + super(id, label, quickOpenService, keybindingService, editorGroupService, editorService); + } +} + export class GlobalQuickOpenAction extends Action { public static ID = 'workbench.action.quickOpen'; diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index a504261df5f..5a7a49892e6 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -11,7 +11,7 @@ import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); import strings = require('vs/base/common/strings'); -import {IAutoFocus, Mode, IEntryRunContext} from 'vs/base/parts/quickopen/common/quickOpen'; +import {IAutoFocus, Mode, IEntryRunContext, IQuickNavigateConfiguration} from 'vs/base/parts/quickopen/common/quickOpen'; import {QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup} from 'vs/base/parts/quickopen/browser/quickOpenModel'; import scorer = require('vs/base/common/scorer'); import {QuickOpenHandler} from 'vs/workbench/browser/quickopen'; @@ -178,8 +178,8 @@ export abstract class EditorGroupPicker extends BaseEditorPicker { return nls.localize('noOpenedEditors', "List of opened editors is currently empty"); } - public getAutoFocus(searchValue: string, isQuickNavigating?: boolean): IAutoFocus { - if (searchValue || !isQuickNavigating) { + public getAutoFocus(searchValue: string, quickNavigateConfiguration: IQuickNavigateConfiguration): IAutoFocus { + if (searchValue || !quickNavigateConfiguration) { return { autoFocusFirstEntry: true }; @@ -191,6 +191,13 @@ export abstract class EditorGroupPicker extends BaseEditorPicker { return super.getAutoFocus(searchValue); } + const isShiftNavigate = (quickNavigateConfiguration && quickNavigateConfiguration.keybindings.some(k => k.hasShift())); + if (isShiftNavigate) { + return { + autoFocusLastEntry: true + }; + } + return { autoFocusFirstEntry: group.count === 1, autoFocusSecondEntry: group.count > 1 diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index a8c28c53c20..83fb90f2528 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -771,7 +771,7 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe let placeHolderLabel = (typeof canRun === 'string') ? canRun : nls.localize('canNotRunPlaceholder', "This quick open handler can not be used in the current context"); const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider); - this.showModel(model, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.isQuickNavigating()), resolvedHandler.getAriaLabel()); + this.showModel(model, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.getQuickNavigateConfiguration()), resolvedHandler.getAriaLabel()); return TPromise.as(null); } @@ -792,9 +792,9 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe if (this.currentResultToken === currentResultToken) { if (!result || !result.entries.length) { const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(resolvedHandler.getEmptyLabel(value))]); - this.showModel(model, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.isQuickNavigating()), resolvedHandler.getAriaLabel()); + this.showModel(model, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.getQuickNavigateConfiguration()), resolvedHandler.getAriaLabel()); } else { - this.showModel(result, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.isQuickNavigating()), resolvedHandler.getAriaLabel()); + this.showModel(result, resolvedHandler.getAutoFocus(value, this.quickOpenWidget.getQuickNavigateConfiguration()), resolvedHandler.getAriaLabel()); } } }); diff --git a/src/vs/workbench/browser/quickopen.ts b/src/vs/workbench/browser/quickopen.ts index 12092bce3ab..e83e4341c1d 100644 --- a/src/vs/workbench/browser/quickopen.ts +++ b/src/vs/workbench/browser/quickopen.ts @@ -14,7 +14,7 @@ import errors = require('vs/base/common/errors'); import {Registry} from 'vs/platform/platform'; import {Action} from 'vs/base/common/actions'; import {KeyMod} from 'vs/base/common/keyCodes'; -import {Mode, IEntryRunContext, IAutoFocus, IModel} from 'vs/base/parts/quickopen/common/quickOpen'; +import {Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration} from 'vs/base/parts/quickopen/common/quickOpen'; import {QuickOpenEntry, IHighlight, QuickOpenEntryGroup, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel'; import {EditorOptions, EditorInput} from 'vs/workbench/common/editor'; import {IResourceInput, IEditorInput} from 'vs/platform/editor/common/editor'; @@ -63,7 +63,7 @@ export class QuickOpenHandler { * Indicates if the handler wishes the quick open widget to automatically select the first result entry or an entry * based on a specific prefix match. */ - public getAutoFocus(searchValue: string, isQuickNavigating?: boolean): IAutoFocus { + public getAutoFocus(searchValue: string, quickNavigateConfiguration?: IQuickNavigateConfiguration): IAutoFocus { return {}; } From 10c2b6a4e4754c2a09061a87311a50405393a218 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 13:57:51 +0200 Subject: [PATCH 095/126] extension widgets, ratings --- src/vs/base/browser/dom.ts | 8 ++ .../common/extensionManagement.ts | 2 + .../node/extensionGalleryService.ts | 12 +-- .../extensions/common/extensionsInput.ts | 5 +- .../electron-browser/extensionEditor.ts | 29 ++++-- .../electron-browser/extensionsModel.ts | 15 +++ .../electron-browser/extensionsViewlet.ts | 5 +- .../electron-browser/extensionsWidgets.ts | 66 +++++++++++++ .../electron-browser/media/EmptyStar.svg | 92 +++++++++++++++++++ .../electron-browser/media/FullStarLight.svg | 92 +++++++++++++++++++ .../electron-browser/media/HalfStarLight.svg | 91 ++++++++++++++++++ .../media/extensionEditor.css | 11 +++ .../media/extensionsWidgets.css | 42 +++++++++ 13 files changed, 454 insertions(+), 16 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/EmptyStar.svg create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/FullStarLight.svg create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/HalfStarLight.svg create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 7d98182ed4f..cc17dacbde2 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -986,4 +986,12 @@ export function removeTabIndexAndUpdateFocus(node: HTMLElement): void { export function getElementsByTagName(tag: string): HTMLElement[] { return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); +} + +export function finalHandler(fn: (event: T)=>any): (event: T)=>any { + return e => { + e.preventDefault(); + e.stopPropagation(); + fn(e); + }; } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 4e34fef5d12..dba7cf5e5fe 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -46,6 +46,8 @@ export interface IGalleryExtension { publisherDisplayName: string; description: string; installCount: number; + rating: number; + ratingCount: number; versions: IGalleryVersion[]; } diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index e8944b65fdd..69ad23c39b5 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -152,12 +152,8 @@ class Query { } } -function getInstallCount(statistics: IRawGalleryExtensionStatistics[]): number { - if (!statistics) { - return 0; - } - - const result = statistics.filter(s => s.statisticName === 'install')[0]; +function getStatistic(statistics: IRawGalleryExtensionStatistics[], name: string): number { + const result = (statistics || []).filter(s => s.statisticName === name)[0]; return result ? result.value : 0; } @@ -180,7 +176,9 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr publisher: galleryExtension.publisher.publisherName, publisherDisplayName: galleryExtension.publisher.displayName, description: galleryExtension.shortDescription || '', - installCount: getInstallCount(galleryExtension.statistics), + installCount: getStatistic(galleryExtension.statistics, 'install'), + rating: getStatistic(galleryExtension.statistics, 'averagerating'), + ratingCount: getStatistic(galleryExtension.statistics, 'ratingcount'), versions }; } diff --git a/src/vs/workbench/parts/extensions/common/extensionsInput.ts b/src/vs/workbench/parts/extensions/common/extensionsInput.ts index 1bd0a1eee3e..c6121bde693 100644 --- a/src/vs/workbench/parts/extensions/common/extensionsInput.ts +++ b/src/vs/workbench/parts/extensions/common/extensionsInput.ts @@ -9,14 +9,15 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { EditorInput } from 'vs/workbench/common/editor'; // TODO@joao: layer breaker -import { IExtension } from '../electron-browser/extensionsModel'; +import { IExtension, ExtensionsModel } from '../electron-browser/extensionsModel'; export class ExtensionsInput extends EditorInput { static get ID() { return 'workbench.extensions.input2'; } + get model(): ExtensionsModel { return this._model; } get extension(): IExtension { return this._extension; } - constructor(private _extension: IExtension) { + constructor(private _model: ExtensionsModel, private _extension: IExtension) { super(); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 0b2e65d070a..0b8157acf3f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -10,27 +10,29 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; -import { append, emmet as $, addClass, removeClass } from 'vs/base/browser/dom'; +import { append, emmet as $, addClass, removeClass, finalHandler } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IRequestService } from 'vs/platform/request/common/request'; -// import { IExtension } from './extensionsModel'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITemplateData } from './extensionsList'; +import { RatingsWidget } from './extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; +import { shell } from 'electron'; +import product from 'vs/platform/product'; export class ExtensionEditor extends BaseEditor { static ID: string = 'workbench.editor.extension'; private icon: HTMLElement; - private name: HTMLElement; + private name: HTMLAnchorElement; private publisher: HTMLElement; private installCount: HTMLElement; - private rating: HTMLElement; + private rating: HTMLAnchorElement; private description: HTMLElement; private body: HTMLElement; @@ -62,12 +64,14 @@ export class ExtensionEditor extends BaseEditor { this.icon = append(header, $('.icon')); const details = append(header, $('.details')); - this.name = append(details, $('.name')); + this.name = append(details, $('a.name')); + this.name.href = '#'; const subtitle = append(details, $('.subtitle')); this.publisher = append(subtitle, $('span.publisher')); this.installCount = append(subtitle, $('span.install')); - this.rating = append(subtitle, $('span.rating')); + this.rating = append(subtitle, $('a.rating')); + this.rating.href = '#'; this.description = append(details, $('p.description')); @@ -87,7 +91,20 @@ export class ExtensionEditor extends BaseEditor { this.publisher.textContent = extension.publisherDisplayName; this.description.textContent = extension.description; + if (product.extensionsGallery) { + const extensionUrl = `${ product.extensionsGallery.itemUrl }?itemName=${ extension.publisher }.${ extension.name }`; + + this.name.onclick = finalHandler(e => shell.openExternal(extensionUrl)); + this.rating.onclick = finalHandler(e => shell.openExternal(`${ extensionUrl }#review-details`)); + } + + if (extension.rating !== null) { + const ratings = new RatingsWidget(this.rating, input.model, extension); + this.transientDisposables.push(ratings); + } + if (!extension.readmeUrl) { + // TODO@Joao this.body.innerHTML = 'no readme :('; } else { addClass(this.body, 'loading'); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index bdd8825c3aa..a5d27419d68 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -30,6 +30,9 @@ export interface IExtension { description: string; readmeUrl: string; iconUrl: string; + installCount: number; + rating: number; + ratingCount: number; } interface IExtensionStateProvider { @@ -107,6 +110,18 @@ class Extension implements IExtension { get state(): ExtensionState { return this.stateProvider(this); } + + get installCount(): number { + return this.gallery ? this.gallery.installCount : null; + } + + get rating(): number { + return this.gallery ? this.gallery.rating : null; + } + + get ratingCount(): number { + return this.gallery ? this.gallery.ratingCount : null; + } } export class ExtensionsModel { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 91492dba36a..ccf54dbbc2a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -92,9 +92,12 @@ export class ExtensionsViewlet extends Viewlet { return; } - return this.editorService.openEditor(new ExtensionsInput(extension)); + return this.editorService.openEditor(new ExtensionsInput(this.model, extension)); }, null, this.disposables); + this.searchBox.value = 'python'; + this.triggerSearch(); + return TPromise.as(null); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts new file mode 100644 index 00000000000..803c7fb0fcd --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/extensionsWidgets'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IExtension, ExtensionsModel } from './extensionsModel'; +import { append, emmet as $, addClass } from 'vs/base/browser/dom'; + +export interface IOptions { + small?: boolean; +} + +export class RatingsWidget implements IDisposable { + + static ID: string = 'workbench.editor.extension'; + + private element: HTMLElement; + private disposables: IDisposable[] = []; + + constructor( + container: HTMLElement, + private model: ExtensionsModel, + private extension: IExtension, + options: IOptions = {} + ) { + this.disposables.push(this.model.onChange(() => this.render())); + this.element = append(container, $('span.extension-ratings')); + + if (options.small) { + addClass(this.element, 'small'); + } + + this.render(); + } + + private render(): void { + const rating = this.extension.rating; + this.element.innerHTML = ''; + + if (rating === null) { + return; + } + + for (let i = 1; i <= 5; i++) { + if (rating >= i) { + append(this.element, $('span.full.star')); + } else if (rating >= i - 0.5) { + append(this.element, $('span.half.star')); + } else { + append(this.element, $('span.empty.star')); + } + } + + const count = append(this.element, $('span.count')); + count.textContent = String(this.extension.ratingCount); + } + + dispose(): void { + this.element.parentElement.removeChild(this.element); + this.disposables = dispose(this.disposables); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/EmptyStar.svg b/src/vs/workbench/parts/extensions/electron-browser/media/EmptyStar.svg new file mode 100644 index 00000000000..f1e005907de --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/EmptyStar.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/FullStarLight.svg b/src/vs/workbench/parts/extensions/electron-browser/media/FullStarLight.svg new file mode 100644 index 00000000000..19c7da2e959 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/FullStarLight.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/HalfStarLight.svg b/src/vs/workbench/parts/extensions/electron-browser/media/HalfStarLight.svg new file mode 100644 index 00000000000..cd84fdd9799 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/HalfStarLight.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index 3f1c943c79f..d1dbbfa211c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -10,6 +10,10 @@ flex-direction: column; } +.extension-editor a { + color: inherit; +} + .extension-editor > .header { display: flex; height: 128px; @@ -44,6 +48,13 @@ padding-top: 10px; } +.extension-editor > .header > .details > .subtitle > span:not(:first-child):not(:empty), +.extension-editor > .header > .details > .subtitle > a:not(:first-child):not(:empty) { + border-left: 1px solid rgba(128, 128, 128, 0.7); + margin-left: 14px; + padding-left: 14px; +} + .extension-editor > .body { flex: 1; overflow-y: scroll; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css new file mode 100644 index 00000000000..6c723d11258 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.extension-ratings { + display: inline-block; +} + +.extension-ratings > .star { + display: inline-block; + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: center center; +} + +.extension-ratings > .star:not(:first-child) { + margin-left: 3px; +} + +.extension-ratings.small > .star { + width: 12px; + height: 12px; +} + +.extension-ratings > .full { + background-image: url('./FullStarLight.svg'); +} + +.extension-ratings > .half { + background-image: url('./HalfStarLight.svg'); +} + +.extension-ratings > .empty { + background-image: url('./EmptyStar.svg'); +} + +.extension-ratings > .count { + font-size: 80%; + margin-left: 6px; +} \ No newline at end of file From 277192fed85fa1868eb3a3119e48b3fa3e3ab0cf Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 14:35:50 +0200 Subject: [PATCH 096/126] extension editor: css --- .../extensions/electron-browser/media/extensionEditor.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index d1dbbfa211c..523e96ba3b3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -20,6 +20,7 @@ background: rgba(128, 128, 128, 0.15); padding: 20px; overflow: hidden; + font-size: 14px; } .extension-editor > .header > .icon { @@ -41,11 +42,13 @@ font-size: 26px; font-weight: 600; line-height: normal; + white-space: nowrap; } .extension-editor > .header > .details > .subtitle { font-size: 18px; padding-top: 10px; + white-space: nowrap; } .extension-editor > .header > .details > .subtitle > span:not(:first-child):not(:empty), From 380244595ac9ce627b4d7215f76ce3aeb76f4750 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 21 Jun 2016 15:37:29 +0200 Subject: [PATCH 097/126] easier to read syntax --- src/vs/editor/contrib/snippet/common/snippet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/snippet/common/snippet.ts b/src/vs/editor/contrib/snippet/common/snippet.ts index a54a4465626..9725e3851ee 100644 --- a/src/vs/editor/contrib/snippet/common/snippet.ts +++ b/src/vs/editor/contrib/snippet/common/snippet.ts @@ -822,7 +822,7 @@ class SnippetController implements ISnippetController { } } - private static _prepareSnippet(editor:editorCommon.ICommonCodeEditor, selection:Selection, snippet:CodeSnippet, overwriteBefore:number, overwriteAfter:number, stripPrefix?:boolean): { typeRange: Range; adaptedSnippet: ICodeSnippet; } { + private static _prepareSnippet(editor:editorCommon.ICommonCodeEditor, selection:Selection, snippet:CodeSnippet, overwriteBefore:number, overwriteAfter:number, stripPrefix = true): { typeRange: Range; adaptedSnippet: ICodeSnippet; } { var model = editor.getModel(); var typeRange = SnippetController._getTypeRangeForSelection(model, selection, overwriteBefore, overwriteAfter); @@ -831,7 +831,7 @@ class SnippetController implements ISnippetController { var nextInSnippet = snippet.lines[0].substr(overwriteBefore); var commonPrefix = strings.commonPrefixLength(nextTextOnLine, nextInSnippet); - if (commonPrefix > 0 && !stripPrefix === false) { + if (commonPrefix > 0 && stripPrefix) { typeRange = typeRange.setEndPosition(typeRange.endLineNumber, typeRange.endColumn + commonPrefix); } } From 65932a90bb83f2ce3c7efc4d9ec20e506c6332a6 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 15:54:22 +0200 Subject: [PATCH 098/126] extension model: periodic update checks --- src/vs/code/node/cliProcessMain.ts | 2 +- .../common/extensionManagement.ts | 1 + .../node/extensionGalleryService.ts | 11 +++--- .../node/extensionManagementUtil.ts | 4 +- .../electron-browser/extensionTipsService.ts | 4 +- .../electron-browser/extensionsModel.ts | 37 ++++++++++++++++++- .../electron-browser/extensionsViewlet.ts | 3 -- 7 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 7b93c1ce8b3..dea192101df 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -77,7 +77,7 @@ class Main { return TPromise.as(null); } - return this.extensionGalleryService.query({ ids: [id] }) + return this.extensionGalleryService.query({ names: [id] }) .then>(null, err => { if (err.responseText) { try { diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index dba7cf5e5fe..8b92068ba9a 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -71,6 +71,7 @@ export const IExtensionGalleryService = createDecorator o.pageSize, 50); @@ -224,12 +224,11 @@ export class ExtensionGalleryService implements IExtensionGalleryService { .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code'); if (text) { - query = query.withFilter(FilterType.SearchText, text) - .withSort(SortBy.NoneOrRelevance); + query = query.withFilter(FilterType.SearchText, text).withSort(SortBy.NoneOrRelevance); } else if (options.ids) { - options.ids.forEach(id => { - query = query.withFilter(FilterType.ExtensionName, id); - }); + query = options.ids.reduce((query, id) => query.withFilter(FilterType.ExtensionId, id), query); + } else if (options.names) { + query = options.names.reduce((query, name) => query.withFilter(FilterType.ExtensionName, name), query); } else { query = query.withSort(SortBy.InstallCount); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index db12d424c91..06984461a1b 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -44,13 +44,13 @@ export function getOutdatedExtensions(extensionsService: IExtensionManagementSer } return extensionsService.getInstalled().then(installed => { - const ids = installed.map(({ manifest }) => `${ manifest.publisher }.${ manifest.name }`); + const names = installed.map(({ manifest }) => `${ manifest.publisher }.${ manifest.name }`); if (installed.length === 0) { return TPromise.as([]); } - return galleryService.query({ ids, pageSize: ids.length }).then(result => { + return galleryService.query({ names, pageSize: names.length }).then(result => { const available = result.firstPage; return available.map(extension => { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index e64d454366f..e7d7be2de86 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -63,9 +63,9 @@ export class ExtensionTipsService implements IExtensionTipsService { } getRecommendations(): Promise { - const ids = Object.keys(this._recommendations); + const names = Object.keys(this._recommendations); - return this._galleryService.query({ ids, pageSize: ids.length }) + return this._galleryService.query({ names, pageSize: names.length }) .then(result => result.firstPage, () => []); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index a5d27419d68..9542c65e0b4 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -8,6 +8,7 @@ import 'vs/css!./media/extensionsViewlet'; import Event, { Emitter } from 'vs/base/common/event'; import { index } from 'vs/base/common/arrays'; +import { ThrottledDelayer } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IPager, mapPager } from 'vs/base/common/paging'; @@ -126,11 +127,14 @@ class Extension implements IExtension { export class ExtensionsModel { - private disposables: IDisposable[] = []; + private static SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours private stateProvider: IExtensionStateProvider; private installing: { id: string; extension: Extension; }[] = []; private installed: Extension[] = []; + private didTriggerSync: boolean = false; + private syncDelayer: ThrottledDelayer; + private disposables: IDisposable[] = []; private _onChange: Emitter = new Emitter(); get onChange(): Event { return this._onChange.event; } @@ -140,9 +144,12 @@ export class ExtensionsModel { @IExtensionGalleryService private galleryService: IExtensionGalleryService ) { this.stateProvider = ext => this.getExtensionState(ext); + this.disposables.push(extensionService.onInstallExtension(({ id, gallery }) => this.onInstallExtension(id, gallery))); this.disposables.push(extensionService.onDidInstallExtension(({ id, local, error }) => this.onDidInstallExtension(id, local, error))); this.disposables.push(extensionService.onUninstallExtension((id) => this.onUninstallExtension(id))); + + this.syncDelayer = new ThrottledDelayer(ExtensionsModel.SyncPeriod); } getLocal(): TPromise { @@ -159,6 +166,11 @@ export class ExtensionsModel { .filter(e => !this.installed.some(installed => installed.local.id === e.id)) .map(e => e.extension); + if (!this.didTriggerSync) { + this.didTriggerSync = true; + this.syncWithGallery(true); + } + return [...this.installed, ...installing]; }); } @@ -167,6 +179,8 @@ export class ExtensionsModel { return this.galleryService.query(options).then(result => { const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : ''); + console.log(installedByGalleryId); + return mapPager(result, gallery => { const id = gallery.id; const installed = installedByGalleryId[id]; @@ -181,6 +195,27 @@ export class ExtensionsModel { }); } + private syncWithGallery(immediate = false): void { + const loop = () => this.doSyncWithGallery().then(() => this.syncWithGallery()); + const delay = immediate ? 0 : ExtensionsModel.SyncPeriod; + + this.syncDelayer.trigger(loop, delay); + } + + private doSyncWithGallery(): TPromise { + const ids = this.installed + .filter(e => !!(e.local && e.local.metadata)) + .map(e => e.local.metadata.id); + + if (ids.length === 0) { + return TPromise.as(null); + } + + console.log('sync', ids); + + return this.queryGallery({ ids, pageSize: ids.length }) as TPromise; + } + canInstall(extension: IExtension): boolean { if (!(extension instanceof Extension)) { return; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index ccf54dbbc2a..69dddf98381 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -95,9 +95,6 @@ export class ExtensionsViewlet extends Viewlet { return this.editorService.openEditor(new ExtensionsInput(this.model, extension)); }, null, this.disposables); - this.searchBox.value = 'python'; - this.triggerSearch(); - return TPromise.as(null); } From 2e412f79a9155bd3eacfdeb8d95d224ee27c670c Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 21 Jun 2016 15:36:24 +0200 Subject: [PATCH 099/126] debug: rename box support validation --- .../parts/debug/browser/debugViewer.ts | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index 0f0e6601ef0..41649aac83b 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -82,19 +82,22 @@ export function renderVariable(tree: tree.ITree, variable: model.Variable, data: } } -function renderRenameBox(debugService: debug.IDebugService, contextViewService: IContextViewService, tree: tree.ITree, element: any, - container: HTMLElement, initialValue: string, placeholder: string, ariaLabel: string): void { +interface IRenameBoxOptions { + initialValue: string; + ariaLabel: string; + placeholder?: string; + validationOptions?: inputbox.IInputValidationOptions; +} + +function renderRenameBox(debugService: debug.IDebugService, contextViewService: IContextViewService, tree: tree.ITree, element: any, container: HTMLElement, options: IRenameBoxOptions): void { let inputBoxContainer = dom.append(container, $('.inputBoxContainer')); let inputBox = new inputbox.InputBox(inputBoxContainer, contextViewService, { - validationOptions: { - validation: null, - showMessage: false - }, - placeholder: placeholder, - ariaLabel: ariaLabel + validationOptions: options.validationOptions, + placeholder: options.placeholder, + ariaLabel: options.ariaLabel }); - inputBox.value = initialValue ? initialValue : ''; + inputBox.value = options.initialValue ? options.initialValue : ''; inputBox.focus(); let disposed = false; @@ -262,7 +265,7 @@ export class CallStackController extends BaseDebugController { return true; } - private focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent|IMouseEvent, preserveFocus: boolean): void { + private focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { this.debugService.setFocusedStackFrameAndEvaluate(stackFrame).done(null, errors.onUnexpectedError); const sideBySide = (event && (event.ctrlKey || event.metaKey)); @@ -637,8 +640,10 @@ export class VariablesRenderer implements tree.IRenderer { this.renderScope(element, templateData); } else { if (element === this.debugService.getViewModel().getSelectedExpression()) { - renderRenameBox(this.debugService, this.contextViewService, tree, element, (templateData).expression, - (element).value, null, nls.localize('variableValueAriaLabel', "Type new variable value")); + renderRenameBox(this.debugService, this.contextViewService, tree, element, (templateData).expression, { + initialValue: (element).value, + ariaLabel: nls.localize('variableValueAriaLabel', "Type new variable value") + }); } else { renderVariable(tree, element, templateData, true); } @@ -833,7 +838,11 @@ export class WatchExpressionsRenderer implements tree.IRenderer { private renderWatchExpression(tree: tree.ITree, watchExpression: debug.IExpression, data: IWatchExpressionTemplateData): void { let selectedExpression = this.debugService.getViewModel().getSelectedExpression(); if ((selectedExpression instanceof model.Expression && selectedExpression.getId() === watchExpression.getId()) || (watchExpression instanceof model.Expression && !watchExpression.name)) { - renderRenameBox(this.debugService, this.contextViewService, tree, watchExpression, data.expression, watchExpression.name, nls.localize('watchExpressionPlaceholder', "Expression to watch"), nls.localize('watchExpressionInputAriaLabel', "Type watch expression")); + renderRenameBox(this.debugService, this.contextViewService, tree, watchExpression, data.expression, { + initialValue: watchExpression.name, + placeholder: nls.localize('watchExpressionPlaceholder', "Expression to watch"), + ariaLabel: nls.localize('watchExpressionInputAriaLabel', "Type watch expression") + }); } data.actionBar.context = watchExpression; @@ -1106,7 +1115,11 @@ export class BreakpointsRenderer implements tree.IRenderer { private renderFunctionBreakpoint(tree: tree.ITree, functionBreakpoint: debug.IFunctionBreakpoint, data: IFunctionBreakpointTemplateData): void { const selected = this.debugService.getViewModel().getSelectedFunctionBreakpoint(); if (!functionBreakpoint.name || (selected && selected.getId() === functionBreakpoint.getId())) { - renderRenameBox(this.debugService, this.contextViewService, tree, functionBreakpoint, data.breakpoint, functionBreakpoint.name, nls.localize('functionBreakpointPlaceholder', "Function to break on"), nls.localize('functionBreakPointInputAriaLabel', "Type function breakpoint")); + renderRenameBox(this.debugService, this.contextViewService, tree, functionBreakpoint, data.breakpoint, { + initialValue: functionBreakpoint.name, + placeholder: nls.localize('functionBreakpointPlaceholder', "Function to break on"), + ariaLabel: nls.localize('functionBreakPointInputAriaLabel', "Type function breakpoint") + }); } else { this.debugService.getModel().areBreakpointsActivated() ? tree.removeTraits('disabled', [functionBreakpoint]) : tree.addTraits('disabled', [functionBreakpoint]); data.name.textContent = functionBreakpoint.name; @@ -1222,7 +1235,7 @@ export class BreakpointsController extends BaseDebugController { return false; } - private openBreakpointSource(breakpoint: debug.IBreakpoint, event: IKeyboardEvent|IMouseEvent, preserveFocus: boolean): void { + private openBreakpointSource(breakpoint: debug.IBreakpoint, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { if (!breakpoint.source.inMemory) { const sideBySide = (event && (event.ctrlKey || event.metaKey)); this.debugService.openOrRevealSource(breakpoint.source, breakpoint.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError); From a106b680c04277bf278eb0fa73fa88cf03f96a24 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 21 Jun 2016 16:08:13 +0200 Subject: [PATCH 100/126] debug: set variable should show an error in a nice way fixes #7807 --- .../parts/debug/browser/debugViewer.ts | 25 ++++++++++++------- .../parts/debug/common/debugModel.ts | 3 +++ .../debug/electron-browser/debugService.ts | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index 41649aac83b..68fc7a20232 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -114,10 +114,13 @@ function renderRenameBox(debugService: debug.IDebugService, contextViewService: debugService.renameFunctionBreakpoint(element.getId(), inputBox.value).done(null, errors.onUnexpectedError); } else if (element instanceof model.FunctionBreakpoint && !element.name) { debugService.removeFunctionBreakpoints(element.getId()).done(null, errors.onUnexpectedError); - } else if (element instanceof model.Variable && renamed) { - debugService.setVariable(element, inputBox.value) - // if everything went fine we need to refresh that tree element since his value updated - .done(() => tree.refresh(element, false), errors.onUnexpectedError); + } else if (element instanceof model.Variable) { + (element).errorMessage = null; + if (renamed) { + debugService.setVariable(element, inputBox.value) + // if everything went fine we need to refresh that tree element since his value updated + .done(() => tree.refresh(element, false), errors.onUnexpectedError); + } } tree.clearHighlight(); @@ -639,13 +642,17 @@ export class VariablesRenderer implements tree.IRenderer { if (templateId === VariablesRenderer.SCOPE_TEMPLATE_ID) { this.renderScope(element, templateData); } else { - if (element === this.debugService.getViewModel().getSelectedExpression()) { - renderRenameBox(this.debugService, this.contextViewService, tree, element, (templateData).expression, { - initialValue: (element).value, - ariaLabel: nls.localize('variableValueAriaLabel', "Type new variable value") + const variable = element; + if (variable === this.debugService.getViewModel().getSelectedExpression() || variable.errorMessage) { + renderRenameBox(this.debugService, this.contextViewService, tree, variable, (templateData).expression, { + initialValue: variable.value, + ariaLabel: nls.localize('variableValueAriaLabel', "Type new variable value"), + validationOptions: { + validation: (value: string) => variable.errorMessage ? ({ content: variable.errorMessage }) : null + } }); } else { - renderVariable(tree, element, templateData, true); + renderVariable(tree, variable, templateData, true); } } } diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 15b79893269..b201cbf8dea 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -278,6 +278,9 @@ export class Expression extends ExpressionContainer implements debug.IExpression export class Variable extends ExpressionContainer implements debug.IExpression { + // Used to show the error message coming from the adapter when setting the value #7807 + public errorMessage: string; + constructor(public parent: debug.IExpressionContainer, reference: number, public name: string, value: string, public available = true) { super(reference, `variable:${ parent.getId() }:${ name }`, true); this.value = massageValue(value); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index e7271fea91d..2a5cd3f7c34 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -492,7 +492,7 @@ export class DebugService implements debug.IDebugService { name: variable.name, value, variablesReference: (variable).parent.reference - }).then(response => variable.value = response.body.value); + }).then(response => variable.value = response.body.value, err => (variable).errorMessage = err.message); } public addWatchExpression(name: string): TPromise { From eaabfabf1d32d1465fcc242e82558e589c82b114 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 16:08:19 +0200 Subject: [PATCH 101/126] UpdateAction --- .../electron-browser/extensionsActions.ts | 71 +++++++++++++++++++ .../electron-browser/extensionsList.ts | 7 +- .../electron-browser/extensionsModel.ts | 7 ++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 1b753d9f91c..c01b954a761 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -16,6 +16,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExtension, ExtensionsModel, ExtensionState } from './extensionsModel'; // import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; // import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import * as semver from 'semver'; // const CloseAction = new Action('action.close', nls.localize('close', "Close")); @@ -288,6 +289,76 @@ export class CombinedInstallAction extends Action { return TPromise.as(null); } + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } +} + +export class UpdateAction extends Action { + + private static EnabledClass = 'extension-update-action octicon octicon-cloud-download'; + private static DisabledClass = `${ UpdateAction.EnabledClass } disabled`; + + private disposables: IDisposable[] = []; + + constructor(private model: ExtensionsModel, private extension: IExtension) { + super('extensions.install', nls.localize('installAction', "Install"), UpdateAction.DisabledClass, false); + + this.disposables.push(this.model.onChange(() => this.updateEnablement())); + this.updateEnablement(); + } + + private updateEnablement(): void { + const canInstall = this.model.canInstall(this.extension); + const isInstalled = this.extension.state === ExtensionState.Installed; + const canUpdate = semver.gt(this.extension.latestVersion, this.extension.version); + + console.log(this.extension.latestVersion, this.extension.version); + + this.enabled = canInstall && isInstalled && canUpdate; + this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass; + } + + run(): TPromise { + return this.model.install(this.extension); + + // this.enabled = false; + + // return this.extensionManagementService.getInstalled() + // .then(installed => installed.some(({ manifest }) => extensionEquals(manifest, extension))) + // .then(isUpdate => { + // return this.extensionManagementService + // .install(extension) + // .then(() => this.onSuccess(extension, isUpdate), err => this.onError(err, extension, isUpdate)) + // .then(() => this.enabled = true) + // .then(() => null); + // }); + } + + // private onSuccess(extension: IGalleryExtension, isUpdate: boolean) { + // this.reportTelemetry(extension, isUpdate, true); + // this.messageService.show(Severity.Info, { + // message: nls.localize('success-installed', "'{0}' was successfully installed. Restart to enable it.", extension.displayName || extension.name), + // actions: [ + // CloseAction, + // this.instantiationService.createInstance(ReloadWindowAction, ReloadWindowAction.ID, nls.localize('restartNow', "Restart Now")) + // ] + // }); + // } + + // private onError(err: Error, extension: IGalleryExtension, isUpdate: boolean) { + // this.reportTelemetry(extension, isUpdate, false); + // this.messageService.show(Severity.Error, err); + // } + + // private reportTelemetry(extension: IGalleryExtension, isUpdate: boolean, success: boolean) { + // const event = isUpdate ? 'extensionGallery:update' : 'extensionGallery:install'; + // const data = assign(getTelemetryData(extension), { success }); + + // this.telemetryService.publicLog(event, data); + // } + dispose(): void { super.dispose(); this.disposables = dispose(this.disposables); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 5ae9f3bf737..3ccec39a17b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, ExtensionsModel } from './extensionsModel'; -import { CombinedInstallAction } from './extensionsActions'; +import { CombinedInstallAction, UpdateAction } from './extensionsActions'; export interface ITemplateData { extension: IExtension; @@ -90,8 +90,9 @@ export class Renderer implements IPagedRenderer { data.actionbar.clear(); const installAction = new CombinedInstallAction(this.model, extension); - data.actionbar.push(installAction, actionOptions); - data.disposables.push(installAction); + const updateAction = new UpdateAction(this.model, extension); + data.actionbar.push([updateAction, installAction], actionOptions); + data.disposables.push(installAction, updateAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 9542c65e0b4..9b5260f3400 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -28,6 +28,7 @@ export interface IExtension { publisher: string; publisherDisplayName: string; version: string; + latestVersion: string; description: string; readmeUrl: string; iconUrl: string; @@ -80,6 +81,10 @@ class Extension implements IExtension { return this.local ? this.local.manifest.version : this.gallery.versions[0].version; } + get latestVersion(): string { + return this.gallery ? this.gallery.versions[0].version : this.local.manifest.version; + } + get description(): string { return this.local ? this.local.manifest.description : this.gallery.description; } @@ -171,6 +176,7 @@ export class ExtensionsModel { this.syncWithGallery(true); } + this._onChange.fire(); return [...this.installed, ...installing]; }); } @@ -187,6 +193,7 @@ export class ExtensionsModel { if (installed) { installed.gallery = gallery; + this._onChange.fire(); return installed; } From faa1b4a0bde852ab7c86de5f86caab7584b681dd Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 16:29:17 +0200 Subject: [PATCH 102/126] dynamic ratings widget --- .../electron-browser/extensionEditor.ts | 6 +-- .../electron-browser/extensionsActions.ts | 2 - .../electron-browser/extensionsList.ts | 7 +++- .../electron-browser/extensionsModel.ts | 4 -- .../electron-browser/extensionsWidgets.ts | 38 ++++++++++++++----- .../media/extensionEditor.css | 2 + 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 0b8157acf3f..23ac3477924 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -98,10 +98,8 @@ export class ExtensionEditor extends BaseEditor { this.rating.onclick = finalHandler(e => shell.openExternal(`${ extensionUrl }#review-details`)); } - if (extension.rating !== null) { - const ratings = new RatingsWidget(this.rating, input.model, extension); - this.transientDisposables.push(ratings); - } + const ratings = new RatingsWidget(this.rating, input.model, extension); + this.transientDisposables.push(ratings); if (!extension.readmeUrl) { // TODO@Joao diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index c01b954a761..8d37432421c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -314,8 +314,6 @@ export class UpdateAction extends Action { const isInstalled = this.extension.state === ExtensionState.Installed; const canUpdate = semver.gt(this.extension.latestVersion, this.extension.version); - console.log(this.extension.latestVersion, this.extension.version); - this.enabled = canInstall && isInstalled && canUpdate; this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 3ccec39a17b..9f491d5551d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -13,6 +13,7 @@ import { IDelegate } from 'vs/base/browser/ui/list/list'; import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging'; import { IExtension, ExtensionsModel } from './extensionsModel'; import { CombinedInstallAction, UpdateAction } from './extensionsActions'; +import { Label } from './extensionsWidgets'; export interface ITemplateData { extension: IExtension; @@ -84,15 +85,17 @@ export class Renderer implements IPagedRenderer { data.extension = extension; data.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; data.name.textContent = extension.displayName; - data.version.textContent = extension.version; data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; data.actionbar.clear(); + const version = new Label(data.version, this.model, extension, e => e.version); + const installAction = new CombinedInstallAction(this.model, extension); const updateAction = new UpdateAction(this.model, extension); data.actionbar.push([updateAction, installAction], actionOptions); - data.disposables.push(installAction, updateAction); + + data.disposables.push(version, installAction, updateAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index 9b5260f3400..d7769010449 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -185,8 +185,6 @@ export class ExtensionsModel { return this.galleryService.query(options).then(result => { const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : ''); - console.log(installedByGalleryId); - return mapPager(result, gallery => { const id = gallery.id; const installed = installedByGalleryId[id]; @@ -218,8 +216,6 @@ export class ExtensionsModel { return TPromise.as(null); } - console.log('sync', ids); - return this.queryGallery({ ids, pageSize: ids.length }) as TPromise; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts index 803c7fb0fcd..6905187c2a9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts @@ -14,24 +14,43 @@ export interface IOptions { small?: boolean; } +export class Label implements IDisposable { + + private listener: IDisposable; + + constructor( + element: HTMLElement, + model: ExtensionsModel, + extension: IExtension, + fn: (extension: IExtension) => string + ) { + const render = () => element.textContent = fn(extension); + render(); + this.listener = model.onChange(render); + } + + dispose(): void { + this.listener = dispose(this.listener); + } +} + export class RatingsWidget implements IDisposable { static ID: string = 'workbench.editor.extension'; - private element: HTMLElement; private disposables: IDisposable[] = []; constructor( - container: HTMLElement, + private container: HTMLElement, private model: ExtensionsModel, private extension: IExtension, options: IOptions = {} ) { this.disposables.push(this.model.onChange(() => this.render())); - this.element = append(container, $('span.extension-ratings')); + addClass(container, 'extension-ratings'); if (options.small) { - addClass(this.element, 'small'); + addClass(container, 'small'); } this.render(); @@ -39,7 +58,7 @@ export class RatingsWidget implements IDisposable { private render(): void { const rating = this.extension.rating; - this.element.innerHTML = ''; + this.container.innerHTML = ''; if (rating === null) { return; @@ -47,20 +66,19 @@ export class RatingsWidget implements IDisposable { for (let i = 1; i <= 5; i++) { if (rating >= i) { - append(this.element, $('span.full.star')); + append(this.container, $('span.full.star')); } else if (rating >= i - 0.5) { - append(this.element, $('span.half.star')); + append(this.container, $('span.half.star')); } else { - append(this.element, $('span.empty.star')); + append(this.container, $('span.empty.star')); } } - const count = append(this.element, $('span.count')); + const count = append(this.container, $('span.count')); count.textContent = String(this.extension.ratingCount); } dispose(): void { - this.element.parentElement.removeChild(this.element); this.disposables = dispose(this.disposables); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index 523e96ba3b3..c2bf2c1d512 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -49,6 +49,8 @@ font-size: 18px; padding-top: 10px; white-space: nowrap; + height: 20px; + line-height: 20px; } .extension-editor > .header > .details > .subtitle > span:not(:first-child):not(:empty), From 1327c91fcd912a750f561a6f12d68dff081cfe9c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 16:33:34 +0200 Subject: [PATCH 103/126] readme error case --- .../electron-browser/extensionEditor.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 23ac3477924..7c541b53af9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -83,7 +83,7 @@ export class ExtensionEditor extends BaseEditor { this.body.innerHTML = ''; - let promise = TPromise.as(null); + let promise = TPromise.wrapError('no readme'); const extension = input.extension; this.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; @@ -101,22 +101,20 @@ export class ExtensionEditor extends BaseEditor { const ratings = new RatingsWidget(this.rating, input.model, extension); this.transientDisposables.push(ratings); - if (!extension.readmeUrl) { - // TODO@Joao - this.body.innerHTML = 'no readme :('; - } else { - addClass(this.body, 'loading'); + addClass(this.body, 'loading'); + if (extension.readmeUrl) { promise = super.setInput(input, options) .then(() => this.requestService.makeRequest({ url: extension.readmeUrl })) .then(response => response.responseText) .then(marked.parse) - .then(html => { - removeClass(this.body, 'loading'); - this.body.innerHTML = html; - }); + .then(html => this.body.innerHTML = html); } + promise = promise + .then(null, err => console.error(err)) + .then(() => removeClass(this.body, 'loading')); + this.transientDisposables.push(toDisposable(() => promise.cancel())); return TPromise.as(null); From 07f039984dfa42b817e631c8d0dad41e2e156d61 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 21 Jun 2016 16:48:27 +0200 Subject: [PATCH 104/126] dark theme: inactive tab to have lower opacity --- .../workbench/browser/parts/editor/media/tabstitle.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitle.css b/src/vs/workbench/browser/parts/editor/media/tabstitle.css index 4ec13f088bf..8b93bb1c9f1 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitle.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitle.css @@ -35,10 +35,18 @@ border-left: 1px solid rgba(128, 128, 128, 0.2); border-bottom: 1px solid rgba(128, 128, 128, 0.2); box-sizing: border-box; - opacity: 0.7 !important; padding-left: 10px; } +.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab, +.hc-black .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab { + opacity: 0.7 !important; +} + +.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab { + opacity: 0.5 !important; +} + .hc-black .monaco-workbench > .part.editor > .content > .one-editor-container > .title.active .tabs-container > .tab.active { border: 1px solid #f38518; } From b9d0c9598f7c5a4900b59537519b6d2689e4e0cb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 16:49:43 +0200 Subject: [PATCH 105/126] search by publisher --- .../electron-browser/extensionEditor.ts | 29 ++++++++++++------- .../extensions/electron-browser/extensions.ts | 12 ++++++++ .../electron-browser/extensionsViewlet.ts | 17 +++++++---- 3 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/extensions.ts diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 7c541b53af9..d1c49cd201a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -12,6 +12,7 @@ import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecy import { Builder } from 'vs/base/browser/builder'; import { append, emmet as $, addClass, removeClass, finalHandler } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -23,6 +24,7 @@ import { RatingsWidget } from './extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { shell } from 'electron'; import product from 'vs/platform/product'; +import { IExtensionsViewlet } from './extensions'; export class ExtensionEditor extends BaseEditor { @@ -30,7 +32,7 @@ export class ExtensionEditor extends BaseEditor { private icon: HTMLElement; private name: HTMLAnchorElement; - private publisher: HTMLElement; + private publisher: HTMLAnchorElement; private installCount: HTMLElement; private rating: HTMLAnchorElement; private description: HTMLElement; @@ -47,7 +49,8 @@ export class ExtensionEditor extends BaseEditor { @IExtensionGalleryService private galleryService: IExtensionGalleryService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService, - @IRequestService private requestService: IRequestService + @IRequestService private requestService: IRequestService, + @IViewletService private viewletService: IViewletService ) { super(ExtensionEditor.ID, telemetryService); this._highlight = null; @@ -68,7 +71,8 @@ export class ExtensionEditor extends BaseEditor { this.name.href = '#'; const subtitle = append(details, $('.subtitle')); - this.publisher = append(subtitle, $('span.publisher')); + this.publisher = append(subtitle, $('a.publisher')); + this.publisher.href = '#'; this.installCount = append(subtitle, $('span.install')); this.rating = append(subtitle, $('a.rating')); this.rating.href = '#'; @@ -83,7 +87,7 @@ export class ExtensionEditor extends BaseEditor { this.body.innerHTML = ''; - let promise = TPromise.wrapError('no readme'); + let promise = TPromise.as(null); const extension = input.extension; this.icon.style.backgroundImage = `url("${ extension.iconUrl }")`; @@ -94,8 +98,13 @@ export class ExtensionEditor extends BaseEditor { if (product.extensionsGallery) { const extensionUrl = `${ product.extensionsGallery.itemUrl }?itemName=${ extension.publisher }.${ extension.name }`; - this.name.onclick = finalHandler(e => shell.openExternal(extensionUrl)); - this.rating.onclick = finalHandler(e => shell.openExternal(`${ extensionUrl }#review-details`)); + this.name.onclick = finalHandler(() => shell.openExternal(extensionUrl)); + this.rating.onclick = finalHandler(() => shell.openExternal(`${ extensionUrl }#review-details`)); + this.publisher.onclick = finalHandler(() => { + this.viewletService.openViewlet('workbench.viewlet.extensions', true) + .then(viewlet => viewlet as IExtensionsViewlet) + .done(viewlet => viewlet.search(`publisher:"${ extension.publisherDisplayName }"`, true)); + }); } const ratings = new RatingsWidget(this.rating, input.model, extension); @@ -108,13 +117,11 @@ export class ExtensionEditor extends BaseEditor { .then(() => this.requestService.makeRequest({ url: extension.readmeUrl })) .then(response => response.responseText) .then(marked.parse) - .then(html => this.body.innerHTML = html); + .then(html => this.body.innerHTML = html) + .then(null, err => console.error(err)) + .then(() => removeClass(this.body, 'loading')); } - promise = promise - .then(null, err => console.error(err)) - .then(() => removeClass(this.body, 'loading')); - this.transientDisposables.push(toDisposable(() => promise.cancel())); return TPromise.as(null); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts new file mode 100644 index 00000000000..6888cfe54df --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * 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 {IViewlet} from 'vs/workbench/common/viewlet'; + +export interface IExtensionsViewlet extends IViewlet { + search(text: string, immediate?: boolean): void; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 69dddf98381..866fe855cfc 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -23,12 +23,13 @@ import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Delegate, Renderer } from './extensionsList'; import { ExtensionsModel, IExtension } from './extensionsModel'; +import { IExtensionsViewlet } from './extensions'; import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -export class ExtensionsViewlet extends Viewlet { +export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { static ID: string = 'workbench.viewlet.extensions'; @@ -61,6 +62,7 @@ export class ExtensionsViewlet extends Viewlet { const header = append(this.root, $('.header')); this.searchBox = append(header, $('input.search-box')); + this.searchBox.type = 'search'; this.searchBox.placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); this.extensionsBox = append(this.root, $('.extensions')); @@ -103,7 +105,7 @@ export class ExtensionsViewlet extends Viewlet { if (visible) { this.searchBox.focus(); this.searchBox.setSelectionRange(0,this.searchBox.value.length); - this.triggerSearch(0); + this.triggerSearch(true); } else { this.list.model = new SinglePagePagedModel([]); } @@ -118,9 +120,14 @@ export class ExtensionsViewlet extends Viewlet { this.list.layout(height - 38); } - private triggerSearch(delay = 500): void { + search(text: string, immediate = false): void { + this.searchBox.value = text; + this.triggerSearch(immediate); + } + + private triggerSearch(immediate = false): void { const text = this.searchBox.value; - this.searchDelayer.trigger(() => this.doSearch(text), text ? delay : 0); + this.searchDelayer.trigger(() => this.doSearch(text), immediate || !text ? 0 : 500); } private doSearch(text: string = ''): TPromise { @@ -145,7 +152,7 @@ export class ExtensionsViewlet extends Viewlet { private onEscape(): void { this.searchBox.value = ''; - this.triggerSearch(0); + this.triggerSearch(true); } private onUpArrow(): void { From a6aa32032dc559aa88cf0f4a9d77ef5d8c3d89c1 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 21 Jun 2016 16:50:37 +0200 Subject: [PATCH 106/126] update node-debug --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 81fcaee940f..0d9b07436fc 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "1e5cde6/node-debug.zip", + "zip": "1253194/node-debug.zip", "output": "" } From d40dba50c9c78ff64616c43adb78dc630307213b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 17:11:08 +0200 Subject: [PATCH 107/126] hide update action if disabled --- .../extensions/electron-browser/extensionsActions.ts | 1 + .../electron-browser/media/extensionActions.css | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 8d37432421c..b9ea2b459ab 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'vs/css!./media/extensionActions'; import nls = require('vs/nls'); import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css new file mode 100644 index 00000000000..889bb56307d --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-action-bar .action-item .icon.extension-update-action.disabled { + display: none; +} \ No newline at end of file From 735148649507fe08365bc3d4a86adc29c4ad3465 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 17:18:25 +0200 Subject: [PATCH 108/126] extension.outdated --- .../extensions/electron-browser/extensionsActions.ts | 4 +--- .../extensions/electron-browser/extensionsModel.ts | 6 ++++++ .../extensions/electron-browser/extensionsViewlet.ts | 12 ++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index b9ea2b459ab..178f8ad8fce 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -17,7 +17,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExtension, ExtensionsModel, ExtensionState } from './extensionsModel'; // import { extensionEquals, getTelemetryData } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; // import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; -import * as semver from 'semver'; // const CloseAction = new Action('action.close', nls.localize('close', "Close")); @@ -313,9 +312,8 @@ export class UpdateAction extends Action { private updateEnablement(): void { const canInstall = this.model.canInstall(this.extension); const isInstalled = this.extension.state === ExtensionState.Installed; - const canUpdate = semver.gt(this.extension.latestVersion, this.extension.version); - this.enabled = canInstall && isInstalled && canUpdate; + this.enabled = canInstall && isInstalled && this.extension.outdated; this.class = this.enabled ? UpdateAction.EnabledClass : UpdateAction.DisabledClass; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts index d7769010449..036361edfa0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsModel.ts @@ -13,6 +13,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IPager, mapPager } from 'vs/base/common/paging'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import * as semver from 'semver'; export enum ExtensionState { Installing, @@ -35,6 +36,7 @@ export interface IExtension { installCount: number; rating: number; ratingCount: number; + outdated: boolean; } interface IExtensionStateProvider { @@ -128,6 +130,10 @@ class Extension implements IExtension { get ratingCount(): number { return this.gallery ? this.gallery.ratingCount : null; } + + get outdated(): boolean { + return semver.gt(this.latestVersion, this.version); + } } export class ExtensionsModel { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 866fe855cfc..eb73c8f571f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -134,12 +134,16 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { const progressRunner = this.progressService.show(true); let promise: TPromise>; - if (text) { - promise = this.model.queryGallery({ text }) - .then(result => new PagedModel(result)); - } else { + if (!text) { promise = this.model.getLocal() .then(result => new SinglePagePagedModel(result)); + } else if (/@outdated/i.test(text)) { + promise = this.model.getLocal() + .then(result => result.filter(e => e.outdated)) + .then(result => new SinglePagePagedModel(result)); + } else { + promise = this.model.queryGallery({ text }) + .then(result => new PagedModel(result)); } return always(promise, () => progressRunner.done()) From 01bbfdc1216349ab1771b37ebe3ca1eeb23e85da Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 17:26:15 +0200 Subject: [PATCH 109/126] actions in editor --- .../electron-browser/extensionEditor.ts | 16 +++++++++++++++- .../electron-browser/extensionsList.ts | 4 ++-- .../media/extensionEditor.css | 19 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index d1c49cd201a..107c0ccdc41 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -25,6 +25,10 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import { shell } from 'electron'; import product from 'vs/platform/product'; import { IExtensionsViewlet } from './extensions'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; +import { CombinedInstallAction, UpdateAction } from './extensionsActions'; + +const actionOptions = { icon: true, label: false }; export class ExtensionEditor extends BaseEditor { @@ -36,6 +40,7 @@ export class ExtensionEditor extends BaseEditor { private installCount: HTMLElement; private rating: HTMLAnchorElement; private description: HTMLElement; + private actionBar: ActionBar; private body: HTMLElement; private _highlight: ITemplateData; @@ -77,7 +82,10 @@ export class ExtensionEditor extends BaseEditor { this.rating = append(subtitle, $('a.rating')); this.rating.href = '#'; - this.description = append(details, $('p.description')); + this.description = append(details, $('.description')); + + const actions = append(details, $('.actions')); + this.actionBar = new ActionBar(actions); this.body = append(root, $('.body')); } @@ -110,6 +118,12 @@ export class ExtensionEditor extends BaseEditor { const ratings = new RatingsWidget(this.rating, input.model, extension); this.transientDisposables.push(ratings); + const installAction = new CombinedInstallAction(input.model, extension); + const updateAction = new UpdateAction(input.model, extension); + this.actionBar.clear(); + this.actionBar.push([updateAction, installAction], actionOptions); + this.transientDisposables.push(updateAction, installAction); + addClass(this.body, 'loading'); if (extension.readmeUrl) { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 9f491d5551d..bc690b66e93 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -87,15 +87,15 @@ export class Renderer implements IPagedRenderer { data.name.textContent = extension.displayName; data.author.textContent = extension.publisherDisplayName; data.description.textContent = extension.description; - data.actionbar.clear(); const version = new Label(data.version, this.model, extension, e => e.version); const installAction = new CombinedInstallAction(this.model, extension); const updateAction = new UpdateAction(this.model, extension); + data.actionbar.clear(); data.actionbar.push([updateAction, installAction], actionOptions); - data.disposables.push(version, installAction, updateAction); + data.disposables.push(version, installAction, updateAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index c2bf2c1d512..d3ce8c045b0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -60,6 +60,25 @@ padding-left: 14px; } +.extension-editor > .header > .details > .description { + margin-top: 14px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.extension-editor > .header > .details > .actions { + margin-top: 14px; +} + +.extension-editor > .header > .details > .actions > .monaco-action-bar { + text-align: initial; +} + +.extension-editor > .header > .details > .actions > .monaco-action-bar > .actions-container { + justify-content: flex-start; +} + .extension-editor > .body { flex: 1; overflow-y: scroll; From e8050437ce7f0c1f877c065809d1368f949aff90 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 17:27:41 +0200 Subject: [PATCH 110/126] remove error handler --- .../parts/extensions/electron-browser/extensionEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 107c0ccdc41..38d033e07bc 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -132,7 +132,7 @@ export class ExtensionEditor extends BaseEditor { .then(response => response.responseText) .then(marked.parse) .then(html => this.body.innerHTML = html) - .then(null, err => console.error(err)) + .then(null, () => null) .then(() => removeClass(this.body, 'loading')); } From e72af78fd0a7414a05ed776d3ae46be804e0d771 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 17:59:14 +0200 Subject: [PATCH 111/126] pimp up extension actions --- .../base/browser/ui/actionbar/actionbar.css | 4 +- src/vs/base/browser/ui/actionbar/actionbar.ts | 7 ++- .../electron-browser/extensionEditor.ts | 4 +- .../electron-browser/extensionsActions.ts | 9 ++-- .../electron-browser/extensionsList.ts | 7 ++- .../media/extensionActions.css | 49 ++++++++++++++++++- .../media/extensionsViewlet.css | 5 ++ 7 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 2cfe0ecafe7..a58a08217a8 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -36,7 +36,7 @@ cursor: default; } -.monaco-action-bar .action-item.active { +.monaco-action-bar.animated .action-item.active { -ms-transform: translate(0, -3px); -webkit-transform: translate(0, -3px); -moz-transform: translate(0, -3px); @@ -77,7 +77,7 @@ margin-right: .8em; } -.monaco-action-bar.vertical .action-item.active { +.monaco-action-bar.animated.vertical .action-item.active { -ms-transform: translate(5px, 0); -webkit-transform: translate(5px, 0); -moz-transform: translate(5px, 0); diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 8c73c19bfde..46207f71a75 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -137,7 +137,7 @@ export class BaseActionItem extends EventEmitter implements IActionItem { public onClick(event: Event): void { DOM.EventHelper.stop(event, true); - + let context: any; if (types.isUndefinedOrNull(this._context)) { context = event; @@ -388,6 +388,7 @@ export interface IActionBarOptions { actionItemProvider?: IActionItemProvider; actionRunner?: IActionRunner; ariaLabel?: string; + animated?: boolean; } let defaultOptions: IActionBarOptions = { @@ -440,6 +441,10 @@ export class ActionBar extends EventEmitter implements IActionRunner { this.domNode = document.createElement('div'); this.domNode.className = 'monaco-action-bar'; + if (options.animated !== false) { + DOM.addClass(this.domNode, 'animated'); + } + let isVertical = this.options.orientation === ActionsOrientation.VERTICAL; if (isVertical) { this.domNode.className += ' vertical'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 38d033e07bc..264370d6c24 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -28,7 +28,7 @@ import { IExtensionsViewlet } from './extensions'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { CombinedInstallAction, UpdateAction } from './extensionsActions'; -const actionOptions = { icon: true, label: false }; +const actionOptions = { icon: true, label: true }; export class ExtensionEditor extends BaseEditor { @@ -85,7 +85,7 @@ export class ExtensionEditor extends BaseEditor { this.description = append(details, $('.description')); const actions = append(details, $('.actions')); - this.actionBar = new ActionBar(actions); + this.actionBar = new ActionBar(actions, { animated: false }); this.body = append(root, $('.body')); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index 178f8ad8fce..b3ef7418e98 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -117,7 +117,7 @@ export class InstallAction extends Action { private disposables: IDisposable[] = []; constructor(private model: ExtensionsModel, private extension: IExtension) { - super('extensions.install', nls.localize('installAction', "Install"), 'octicon octicon-cloud-download', false); + super('extensions.install', nls.localize('installAction', "Install"), 'extension-action install', false); this.disposables.push(this.model.onChange(() => this.updateEnablement())); this.updateEnablement(); @@ -177,7 +177,7 @@ export class UninstallAction extends Action { private disposables: IDisposable[] = []; constructor(private model: ExtensionsModel, private extension: IExtension) { - super('extensions.uninstall', nls.localize('uninstall', "Uninstall"), 'octicon octicon-x', false); + super('extensions.uninstall', nls.localize('uninstall', "Uninstall"), 'extension-action uninstall', false); this.disposables.push(this.model.onChange(() => this.updateEnablement())); this.updateEnablement(); @@ -194,7 +194,6 @@ export class UninstallAction extends Action { return TPromise.as(null); } - return this.model.uninstall(this.extension); // this.enabled = false; @@ -297,13 +296,13 @@ export class CombinedInstallAction extends Action { export class UpdateAction extends Action { - private static EnabledClass = 'extension-update-action octicon octicon-cloud-download'; + private static EnabledClass = 'extension-action update'; private static DisabledClass = `${ UpdateAction.EnabledClass } disabled`; private disposables: IDisposable[] = []; constructor(private model: ExtensionsModel, private extension: IExtension) { - super('extensions.install', nls.localize('installAction', "Install"), UpdateAction.DisabledClass, false); + super('extensions.update', nls.localize('updateAction', "Update"), UpdateAction.DisabledClass, false); this.disposables.push(this.model.onChange(() => this.updateEnablement())); this.updateEnablement(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index bc690b66e93..69cf962cceb 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -32,7 +32,7 @@ export class Delegate implements IDelegate { getTemplateId() { return 'extension'; } } -const actionOptions = { icon: true, label: false }; +const actionOptions = { icon: true, label: true }; export class Renderer implements IPagedRenderer { @@ -57,7 +57,7 @@ export class Renderer implements IPagedRenderer { const version = append(header, $('span.version.ellipsis')); const author = append(header, $('span.author.ellipsis')); const description = append(details, $('.description.ellipsis')); - const actionbar = new ActionBar(details); + const actionbar = new ActionBar(details, { animated: false }); const disposables = []; const result = { extension: null, element, icon, name, version, author, description, actionbar, disposables }; @@ -89,13 +89,12 @@ export class Renderer implements IPagedRenderer { data.description.textContent = extension.description; const version = new Label(data.version, this.model, extension, e => e.version); - const installAction = new CombinedInstallAction(this.model, extension); const updateAction = new UpdateAction(this.model, extension); data.actionbar.clear(); data.actionbar.push([updateAction, installAction], actionOptions); - data.disposables.push(version, installAction, updateAction); + data.disposables.push(version, installAction, updateAction); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css index 889bb56307d..d27e14f9f8a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css @@ -3,6 +3,53 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-action-bar .action-item .icon.extension-update-action.disabled { +.monaco-action-bar .action-item .action-label.extension-action { + border: 1px solid #CCC; + color: #6C6C6C; + background-color: #E2E2E2; + padding: 0 5px; + line-height: initial; +} + +.monaco-action-bar .action-item:not(.disabled):hover .action-label.extension-action { + background-color: #D9D9D9; +} + +.monaco-action-bar .action-item:not(.disabled):active .action-label.extension-action { + background-color: #C9C9C9; +} + +.vs-dark .monaco-action-bar .action-item .action-label.extension-action { + border: 1px solid #545454; + color: #CCC; + background-color: #3A3A3A; +} + +.vs-dark .monaco-action-bar .action-item:not(.disabled):hover .action-label.extension-action { + background-color: #464646; +} + +.vs-dark .monaco-action-bar .action-item:not(.disabled):active .action-label.extension-action { + background-color: #505050; +} + +.monaco-action-bar .action-item .action-label.extension-action.install, +.monaco-action-bar .action-item .action-label.extension-action.update { + color: white; + background-color: #327e36; + border-color: #519A55; +} + +.monaco-action-bar .action-item:not(.disabled):hover .action-label.extension-action.install, +.monaco-action-bar .action-item:not(.disabled):hover .action-label.extension-action.update { + background-color: #478E4B; +} + +.monaco-action-bar .action-item:not(.disabled):active .action-label.extension-action.install, +.monaco-action-bar .action-item:not(.disabled):active .action-label.extension-action.update { + background-color: #6DA770; +} + +.monaco-action-bar .action-item.disabled .action-label.extension-action.update { display: none; } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css index b4c880b5eae..b66e7ae2142 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsViewlet.css @@ -80,6 +80,11 @@ padding-left: 6px; } +.extensions-viewlet > .extensions .extension > .details > .monaco-action-bar .action-label { + margin-right: 0; + margin-left: 0.3em; +} + .extensions-viewlet > .extensions .extension .ellipsis { overflow: hidden; white-space: nowrap; From c288229f0a1814a325c245bde4309dac57769a9a Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 21 Jun 2016 17:59:58 +0200 Subject: [PATCH 112/126] debug: fix rendering glithc with set variable error --- src/vs/workbench/parts/debug/browser/media/debugViewlet.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css index ee321174655..530cd0f0db3 100644 --- a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css @@ -246,6 +246,7 @@ .debug-viewlet .monaco-inputbox > .wrapper > .input { padding: 0px; + color: initial; } .debug-viewlet .debug-action.add-watch-expression, From c56ebcddc153a33513914b3c9d090d7ed4e995fb Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 18:06:14 +0200 Subject: [PATCH 113/126] show install count --- .../extensions/electron-browser/extensionEditor.ts | 11 +++++++++-- .../electron-browser/media/extensionEditor.css | 9 ++++++++- .../electron-browser/media/extensionsWidgets.css | 1 - 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 264370d6c24..4597e07d319 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -20,7 +20,7 @@ import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common import { ExtensionsInput } from '../common/extensionsInput'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITemplateData } from './extensionsList'; -import { RatingsWidget } from './extensionsWidgets'; +import { RatingsWidget, Label } from './extensionsWidgets'; import { EditorOptions } from 'vs/workbench/common/editor'; import { shell } from 'electron'; import product from 'vs/platform/product'; @@ -78,7 +78,11 @@ export class ExtensionEditor extends BaseEditor { const subtitle = append(details, $('.subtitle')); this.publisher = append(subtitle, $('a.publisher')); this.publisher.href = '#'; - this.installCount = append(subtitle, $('span.install')); + + const install = append(subtitle, $('span.install')); + append(install, $('span.octicon.octicon-cloud-download')); + this.installCount = append(install, $('span.count')); + this.rating = append(subtitle, $('a.rating')); this.rating.href = '#'; @@ -115,6 +119,9 @@ export class ExtensionEditor extends BaseEditor { }); } + const install = new Label(this.installCount, input.model, extension, e => `${ e.installCount }`); + this.transientDisposables.push(install); + const ratings = new RatingsWidget(this.rating, input.model, extension); this.transientDisposables.push(ratings); diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index d3ce8c045b0..e0d35b3296a 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -46,13 +46,20 @@ } .extension-editor > .header > .details > .subtitle { - font-size: 18px; padding-top: 10px; white-space: nowrap; height: 20px; line-height: 20px; } +.extension-editor > .header > .details > .subtitle > .publisher { + font-size: 18px; +} + +.extension-editor > .header > .details > .subtitle > .install > .count { + margin-left: 6px; +} + .extension-editor > .header > .details > .subtitle > span:not(:first-child):not(:empty), .extension-editor > .header > .details > .subtitle > a:not(:first-child):not(:empty) { border-left: 1px solid rgba(128, 128, 128, 0.7); diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css index 6c723d11258..680ce6acfd7 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionsWidgets.css @@ -37,6 +37,5 @@ } .extension-ratings > .count { - font-size: 80%; margin-left: 6px; } \ No newline at end of file From 4e398e177aac5b55bc81ef530681dea83c42a568 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 18:17:49 +0200 Subject: [PATCH 114/126] search for @popular --- .../common/extensionManagement.ts | 18 +++++++++ .../node/extensionGalleryService.ts | 38 +++++++++---------- .../electron-browser/extensionsViewlet.ts | 5 ++- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 8b92068ba9a..4d652721b4b 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -68,11 +68,29 @@ export interface ILocalExtension { export const IExtensionManagementService = createDecorator('extensionManagementService'); export const IExtensionGalleryService = createDecorator('extensionGalleryService'); +export enum SortBy { + NoneOrRelevance = 0, + LastUpdatedDate = 1, + Title = 2, + PublisherName = 3, + InstallCount = 4, + PublishedDate = 5, + AverageRating = 6 +} + +export enum SortOrder { + Default = 0, + Ascending = 1, + Descending = 2 +} + export interface IQueryOptions { text?: string; ids?: string[]; names?: string[]; pageSize?: number; + sortBy?: SortBy; + sortOrder?: SortOrder; } export interface IExtensionGalleryService { diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 213ef342ba5..054ad3ecf23 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TPromise } from 'vs/base/common/winjs.base'; -import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, SortBy, SortOrder } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -63,22 +63,6 @@ enum FilterType { SearchText = 10 } -enum SortBy { - NoneOrRelevance = 0, - LastUpdatedDate = 1, - Title = 2, - PublisherName = 3, - InstallCount = 4, - PublishedDate = 5, - AverageRating = 6 -} - -enum SortOrder { - Default = 0, - Ascending = 1, - Descending = 2 -} - interface ICriterium { filterType: FilterType; value?: string; @@ -130,8 +114,12 @@ class Query { return new Query(assign({}, this.state, { criteria })); } - withSort(sortBy: SortBy, sortOrder = SortOrder.Default): Query { - return new Query(assign({}, this.state, { sortBy, sortOrder })); + withSortBy(sortBy: SortBy): Query { + return new Query(assign({}, this.state, { sortBy })); + } + + withSortOrder(sortOrder): Query { + return new Query(assign({}, this.state, { sortOrder })); } withFlags(...flags: Flags[]): Query { @@ -224,13 +212,21 @@ export class ExtensionGalleryService implements IExtensionGalleryService { .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code'); if (text) { - query = query.withFilter(FilterType.SearchText, text).withSort(SortBy.NoneOrRelevance); + query = query.withFilter(FilterType.SearchText, text).withSortBy(SortBy.NoneOrRelevance); } else if (options.ids) { query = options.ids.reduce((query, id) => query.withFilter(FilterType.ExtensionId, id), query); } else if (options.names) { query = options.names.reduce((query, name) => query.withFilter(FilterType.ExtensionName, name), query); } else { - query = query.withSort(SortBy.InstallCount); + query = query.withSortBy(SortBy.InstallCount); + } + + if (typeof options.sortBy === 'number') { + query = query.withSortBy(options.sortBy); + } + + if (typeof options.sortOrder === 'number') { + query = query.withSortOrder(options.sortOrder); } return this.queryGallery(query).then(({ galleryExtensions, total }) => { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index eb73c8f571f..40e04f6c4e6 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -24,7 +24,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { Delegate, Renderer } from './extensionsList'; import { ExtensionsModel, IExtension } from './extensionsModel'; import { IExtensionsViewlet } from './extensions'; -import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, SortBy } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from '../common/extensionsInput'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -141,6 +141,9 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { promise = this.model.getLocal() .then(result => result.filter(e => e.outdated)) .then(result => new SinglePagePagedModel(result)); + } else if (/@popular/i.test(text)) { + promise = this.model.queryGallery({ sortBy: SortBy.InstallCount }) + .then(result => new PagedModel(result)); } else { promise = this.model.queryGallery({ text }) .then(result => new PagedModel(result)); From 2dc1d5157a5f5cf3bed1b35df2fa304805d46cc9 Mon Sep 17 00:00:00 2001 From: Andre Weinand Date: Tue, 21 Jun 2016 18:33:27 +0200 Subject: [PATCH 115/126] update node-debug --- extensions/node-debug/node-debug.azure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/node-debug/node-debug.azure.json b/extensions/node-debug/node-debug.azure.json index 0d9b07436fc..16f70569cb6 100644 --- a/extensions/node-debug/node-debug.azure.json +++ b/extensions/node-debug/node-debug.azure.json @@ -1,6 +1,6 @@ { "account": "monacobuild", "container": "debuggers", - "zip": "1253194/node-debug.zip", + "zip": "c9a5762/node-debug.zip", "output": "" } From 6938e9c4ab74427be0c17d640f9c336d50fb7858 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 19:11:40 +0200 Subject: [PATCH 116/126] remove urls --- product.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/product.json b/product.json index 670b6d8ab4e..21b2fc9b99c 100644 --- a/product.json +++ b/product.json @@ -7,9 +7,4 @@ "licenseUrl": "https://github.com/Microsoft/vscode/blob/master/LICENSE.txt", "darwinBundleIdentifier": "com.visualstudio.code.oss", "reportIssueUrl": "https://github.com/Microsoft/vscode/issues/new" - ,"extensionsGallery": { - "serviceUrl": "https://marketplace.visualstudio.com/_apis/public/gallery", - "cacheUrl": "https://vscode.blob.core.windows.net/gallery/index", - "itemUrl": "https://marketplace.visualstudio.com/items" - } } \ No newline at end of file From 16676b2d1418313e949007ce98c95ca4e1cb28d9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 21 Jun 2016 10:12:09 -0700 Subject: [PATCH 117/126] Add os.release to help > report issues Fixes #7788 --- src/vs/code/electron-main/menus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 6a29abf74bb..09519b1e3f6 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -20,7 +20,7 @@ import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; export function generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string): string { - const osVersion = `${ os.type() } ${ os.arch() }`; + const osVersion = `${ os.type() } ${ os.arch() } ${ os.release() }`; const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&'; const body = encodeURIComponent( `- VSCode Version: ${name} ${version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'}) From 06d108b4a0aa6c031e7c1e61a463c069809d6019 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 19:44:31 +0200 Subject: [PATCH 118/126] fix extensionsViewlet bundling --- src/vs/workbench/buildfile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/buildfile.js b/src/vs/workbench/buildfile.js index efa046f5145..a644b544060 100644 --- a/src/vs/workbench/buildfile.js +++ b/src/vs/workbench/buildfile.js @@ -35,6 +35,8 @@ exports.collectModules = function(excludes) { createModuleDescription('vs/workbench/parts/debug/browser/repl', excludes), createModuleDescription('vs/workbench/parts/debug/node/telemetryApp', []), + createModuleDescription('vs/workbench/parts/extensions/electron-browser/extensionsViewlet', excludes), + createModuleDescription('vs/workbench/parts/markers/browser/markersPanel', excludes), createModuleDescription('vs/workbench/parts/terminal/electron-browser/terminalPanel', excludes), From 5474147bb83618975409dad7d8aa96151d7d1ea1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Jun 2016 21:26:29 +0200 Subject: [PATCH 119/126] load extension editor --- .../extensions/electron-browser/extensions.contribution.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index 7652935305b..912cd220668 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -19,6 +19,7 @@ import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensions // import { EditorInput } from 'vs/workbench/common/editor'; // import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; +import { ExtensionEditor } from './extensionEditor'; // class ExtensionsInputFactory implements IEditorInputFactory { @@ -46,7 +47,7 @@ Registry.as(OutputExtensions.OutputChannels) // .registerEditorInputFactory(ExtensionsInput.ID, ExtensionsInputFactory); const editorDescriptor = new EditorDescriptor( - 'workbench.editor.extension', + ExtensionEditor.ID, localize('extension', "Extension"), 'vs/workbench/parts/extensions/electron-browser/extensionEditor', 'ExtensionEditor' From 7e72a4d17ad42eb06717014ad1f8890b7f967475 Mon Sep 17 00:00:00 2001 From: kieferrm Date: Tue, 21 Jun 2016 20:22:31 -0700 Subject: [PATCH 120/126] fix toggle markdown preview/source \w keybinding --- extensions/markdown/src/extension.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 99486ad5451..2632b975e78 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -76,7 +76,11 @@ function showPreview(resource?: Uri, sideBySide: boolean = false) { } if (!(resource instanceof Uri)) { - // nothing found that could be shown + if (!vscode.window.activeTextEditor) { + // this is most likely toggling the preview + return vscode.commands.executeCommand('markdown.showSource'); + } + // nothing found that could be shown or toggled return; } @@ -107,6 +111,10 @@ function getViewColumn(sideBySide): ViewColumn { } function showSource(mdUri: Uri) { + if (!mdUri) { + return vscode.commands.executeCommand('workbench.action.navigateBack'); + } + const docUri = Uri.parse(mdUri.query); for (let editor of vscode.window.visibleTextEditors) { From 65d93c9408af2aeea0b1ab4d59b1400359b08503 Mon Sep 17 00:00:00 2001 From: kieferrm Date: Tue, 21 Jun 2016 20:24:08 -0700 Subject: [PATCH 121/126] Fix up duplicated names in command pallete --- extensions/markdown/package.json | 5 +++-- extensions/markdown/package.nls.json | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 69be3160b00..7b907fa6d3e 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -13,7 +13,8 @@ ], "activationEvents": [ "onCommand:markdown.showPreview", - "onCommand:markdown.showPreviewToSide" + "onCommand:markdown.showPreviewToSide", + "onCommand:markdown.showSource" ], "contributes": { "languages": [ @@ -60,7 +61,7 @@ }, { "command": "markdown.showSource", - "title": "%markdown.previewMarkdown.title%", + "title": "%markdown.showSource.title%", "category": "%markdown.category%", "icon": { "light": "./media/ViewSource.svg", diff --git a/extensions/markdown/package.nls.json b/extensions/markdown/package.nls.json index 8c3b2a994bc..f5269c03855 100644 --- a/extensions/markdown/package.nls.json +++ b/extensions/markdown/package.nls.json @@ -1,6 +1,7 @@ { "markdown.category" : "Markdown", "markdown.openPreview" : "Open Preview", - "markdown.previewMarkdown.title" : "Toggle Preview", - "markdown.previewMarkdownSide.title" : "Open Preview to the Side" + "markdown.previewMarkdown.title" : "Show Preview", + "markdown.previewMarkdownSide.title" : "Open Preview to the Side", + "markdown.showSource.title" : "Show Source" } \ No newline at end of file From 3410cb13ac3732b161b1c1c554c44c197da6a5ee Mon Sep 17 00:00:00 2001 From: kieferrm Date: Tue, 21 Jun 2016 20:26:32 -0700 Subject: [PATCH 122/126] fix double quotes --- extensions/markdown/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 2632b975e78..01bd73dd330 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; -import { ExtensionContext, TextDocumentContentProvider, EventEmitter, Event, Uri, ViewColumn } from "vscode"; +import { ExtensionContext, TextDocumentContentProvider, EventEmitter, Event, Uri, ViewColumn } from 'vscode'; const hljs = require('highlight.js'); const mdnh = require('markdown-it-named-headers'); From b9b2a6d8958e362e32ac6fc1dd6ae4d7041eea5b Mon Sep 17 00:00:00 2001 From: kieferrm Date: Tue, 21 Jun 2016 20:31:27 -0700 Subject: [PATCH 123/126] refactoring --- extensions/markdown/src/extension.ts | 43 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index 01bd73dd330..a1ac8066bdc 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -9,21 +9,8 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { ExtensionContext, TextDocumentContentProvider, EventEmitter, Event, Uri, ViewColumn } from 'vscode'; -const hljs = require('highlight.js'); -const mdnh = require('markdown-it-named-headers'); -const md = require('markdown-it')({ - html: true, - highlight: function (str, lang) { - if (lang && hljs.getLanguage(lang)) { - try { - return `
${hljs.highlight(lang, str, true).value}
`; - } catch (error) { } - } - return `
${md.utils.escapeHtml(str)}
`; - } -}).use(mdnh, {}); - export function activate(context: ExtensionContext) { + let provider = new MDDocumentContentProvider(context); let registration = vscode.workspace.registerTextDocumentContentProvider('markdown', provider); @@ -79,7 +66,7 @@ function showPreview(resource?: Uri, sideBySide: boolean = false) { if (!vscode.window.activeTextEditor) { // this is most likely toggling the preview return vscode.commands.executeCommand('markdown.showSource'); - } + } // nothing found that could be shown or toggled return; } @@ -128,14 +115,38 @@ function showSource(mdUri: Uri) { }); } + +interface IRenderer { + render(text: string) : string; +} + class MDDocumentContentProvider implements TextDocumentContentProvider { private _context: ExtensionContext; private _onDidChange = new EventEmitter(); private _waiting : boolean; + private _renderer : IRenderer; constructor(context: ExtensionContext) { this._context = context; this._waiting = false; + this._renderer = this.createRenderer(); + } + + private createRenderer() : IRenderer { + const hljs = require('highlight.js'); + const mdnh = require('markdown-it-named-headers'); + const md = require('markdown-it')({ + html: true, + highlight: function (str, lang) { + if (lang && hljs.getLanguage(lang)) { + try { + return `
${hljs.highlight(lang, str, true).value}
`; + } catch (error) { } + } + return `
${md.utils.escapeHtml(str)}
`; + } + }).use(mdnh, {}); + return md; } private getMediaPath(mediaFile) { @@ -179,7 +190,7 @@ class MDDocumentContentProvider implements TextDocumentContentProvider { '' ).join('\n'); - const body = md.render(document.getText()); + const body = this._renderer.render(document.getText()); const tail = [ '', From b985edc9f5441678cf071fc7925a569e623e7431 Mon Sep 17 00:00:00 2001 From: kieferrm Date: Tue, 21 Jun 2016 20:32:50 -0700 Subject: [PATCH 124/126] introduce activation telemetry --- extensions/markdown/package.json | 4 +- extensions/markdown/src/extension.ts | 37 ++++++++++++++++++- .../typings/vscode-extension-telemetry.d.ts | 6 +++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 extensions/markdown/src/typings/vscode-extension-telemetry.d.ts diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index 7b907fa6d3e..e4f4944e422 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -4,6 +4,7 @@ "description": "Markdown for VS Code", "version": "0.2.0", "publisher": "Microsoft", + "aiKey":"AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "^1.0.0" }, @@ -111,6 +112,7 @@ "dependencies": { "highlight.js": "^9.3.0", "markdown-it": "^6.0.1", - "markdown-it-named-headers": "0.0.4" + "markdown-it-named-headers": "0.0.4", + "vscode-extension-telemetry": "^0.0.5" } } \ No newline at end of file diff --git a/extensions/markdown/src/extension.ts b/extensions/markdown/src/extension.ts index a1ac8066bdc..b2b8c42a4fb 100644 --- a/extensions/markdown/src/extension.ts +++ b/extensions/markdown/src/extension.ts @@ -8,9 +8,22 @@ import * as vscode from 'vscode'; import * as path from 'path'; import { ExtensionContext, TextDocumentContentProvider, EventEmitter, Event, Uri, ViewColumn } from 'vscode'; +import TelemetryReporter from 'vscode-extension-telemetry'; + + +interface IPackageInfo { + name: string; + version: string; + aiKey: string; +} + +var telemetryReporter: TelemetryReporter; export function activate(context: ExtensionContext) { + let packageInfo = getPackageInfo(context); + telemetryReporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); + let provider = new MDDocumentContentProvider(context); let registration = vscode.workspace.registerTextDocumentContentProvider('markdown', provider); @@ -53,8 +66,9 @@ function getMarkdownUri(uri: Uri) { return uri.with({ scheme: 'markdown', path: uri.path + '.rendered', query: uri.toString() }); } -function showPreview(resource?: Uri, sideBySide: boolean = false) { +function showPreview(uri?: Uri, sideBySide: boolean = false) { + let resource = uri; if (!(resource instanceof Uri)) { if (vscode.window.activeTextEditor) { // we are relaxed and don't check for markdown files @@ -71,10 +85,17 @@ function showPreview(resource?: Uri, sideBySide: boolean = false) { return; } - return vscode.commands.executeCommand('vscode.previewHtml', + let thenable = vscode.commands.executeCommand('vscode.previewHtml', getMarkdownUri(resource), getViewColumn(sideBySide), `Preview '${path.basename(resource.fsPath)}'`); + + telemetryReporter.sendTelemetryEvent('openPreview', { + where : sideBySide ? 'sideBySide' : 'inPlace', + how : (uri instanceof Uri) ? 'action' : 'pallete' + }); + + return thenable; } function getViewColumn(sideBySide): ViewColumn { @@ -115,6 +136,18 @@ function showSource(mdUri: Uri) { }); } +function getPackageInfo(context: ExtensionContext): IPackageInfo { + let extensionPackage = require(context.asAbsolutePath('./package.json')); + if (extensionPackage) { + return { + name: extensionPackage.name, + version: extensionPackage.version, + aiKey: extensionPackage.aiKey + }; + } + return null; +} + interface IRenderer { render(text: string) : string; diff --git a/extensions/markdown/src/typings/vscode-extension-telemetry.d.ts b/extensions/markdown/src/typings/vscode-extension-telemetry.d.ts new file mode 100644 index 00000000000..4b2981b9b24 --- /dev/null +++ b/extensions/markdown/src/typings/vscode-extension-telemetry.d.ts @@ -0,0 +1,6 @@ +declare module 'vscode-extension-telemetry' { + export default class TelemetryReporter { + constructor(extensionId: string,extensionVersion: string, key: string); + sendTelemetryEvent(eventName: string, properties?: { [key: string]: string }, measures?: { [key: string]: number }): void; + } +} \ No newline at end of file From ddc27260714910cd4400edf12688a78f6f2e33b5 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 22 Jun 2016 09:31:23 +0200 Subject: [PATCH 125/126] [standalone] add markers to code action provider API --- build/monaco/monaco.d.ts.recipe | 2 +- .../browser/standalone/standaloneLanguages.ts | 39 ++++++++++++++++++- src/vs/editor/common/modes.ts | 1 + src/vs/monaco.d.ts | 35 +++++++++++------ 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index 4ca3735197c..4a447c07f06 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -69,7 +69,7 @@ export interface ICommandHandler { declare module monaco.languages { -#includeAll(vs/editor/browser/standalone/standaloneLanguages;modes.=>;editorCommon.=>editor.): +#includeAll(vs/editor/browser/standalone/standaloneLanguages;modes.=>;editorCommon.=>editor.;IMarkerData=>editor.IMarkerData): #include(vs/editor/common/modes/languageConfigurationRegistry): CommentRule, LanguageConfiguration #include(vs/editor/common/modes/supports/onEnter): IndentationRule, OnEnterRule #include(vs/editor/common/modes/supports/electricCharacter): IBracketElectricCharacterContribution, IDocComment diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index 4ddedb0dc5b..022830454c7 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -26,6 +26,7 @@ import {toThenable} from 'vs/base/common/async'; import {compile} from 'vs/editor/common/modes/monarch/monarchCompile'; import {createTokenizationSupport} from 'vs/editor/common/modes/monarch/monarchLexer'; import {LanguageConfigurationRegistry} from 'vs/editor/common/modes/languageConfigurationRegistry'; +import {IMarkerData} from 'vs/platform/markers/common/markers'; /** * Register information about a new language. @@ -148,8 +149,17 @@ export function registerCodeLensProvider(languageId:string, provider:modes.CodeL /** * Register a code action provider (used by e.g. quick fix). */ -export function registerCodeActionProvider(languageId:string, provider:modes.CodeActionProvider): IDisposable { - return modes.CodeActionProviderRegistry.register(languageId, provider); +export function registerCodeActionProvider(languageId:string, provider:CodeActionProvider): IDisposable { + return modes.CodeActionProviderRegistry.register(languageId, { + provideCodeActions: (model:editorCommon.IReadOnlyModel, range:Range, token: CancellationToken): modes.CodeAction[] | Thenable => { + startup.initStaticServicesIfNecessary(); + var markerService = ensureStaticPlatformServices(null).markerService; + let markers = markerService.read({resource: model.uri }).filter(m => { + return Range.areIntersectingOrTouching(m, range); + }); + return provider.provideCodeActions(model, range, { markers }, token); + } + }); } /** @@ -197,6 +207,31 @@ export function registerCompletionItemProvider(languageId:string, provider:Compl }); } +/** + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ +export interface CodeActionContext { + + /** + * An array of diagnostics. + * + * @readonly + */ + markers: IMarkerData[]; +} + +/** + * The code action interface defines the contract between extensions and + * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + */ +export interface CodeActionProvider { + /** + * Provide commands for the given document and range. + */ + provideCodeActions(model:editorCommon.IReadOnlyModel, range:Range, context: CodeActionContext, token: CancellationToken): modes.CodeAction[] | Thenable; +} + /** * Completion item kinds. */ diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f498798c0ff..687c68f72ac 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -418,6 +418,7 @@ export interface CodeAction { /** * The code action interface defines the contract between extensions and * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + * @internal */ export interface CodeActionProvider { /** diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 7fa814ce385..cf69cd93089 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3841,6 +3841,30 @@ declare module monaco.languages { */ export function registerCompletionItemProvider(languageId: string, provider: CompletionItemProvider): IDisposable; + /** + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ + export interface CodeActionContext { + /** + * An array of diagnostics. + * + * @readonly + */ + markers: editor.IMarkerData[]; + } + + /** + * The code action interface defines the contract between extensions and + * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. + */ + export interface CodeActionProvider { + /** + * Provide commands for the given document and range. + */ + provideCodeActions(model: editor.IReadOnlyModel, range: Range, context: CodeActionContext, token: CancellationToken): CodeAction[] | Thenable; + } + /** * Completion item kinds. */ @@ -4175,17 +4199,6 @@ declare module monaco.languages { score: number; } - /** - * The code action interface defines the contract between extensions and - * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. - */ - export interface CodeActionProvider { - /** - * Provide commands for the given document and range. - */ - provideCodeActions(model: editor.IReadOnlyModel, range: Range, token: CancellationToken): CodeAction[] | Thenable; - } - /** * Represents a parameter of a callable-signature. A parameter can * have a label and a doc-comment. From 88f88a90938243434488ed72a81498651782607b Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 22 Jun 2016 10:17:03 +0200 Subject: [PATCH 126/126] Update TS grammar with fix 11. --- .../javascript/syntaxes/JavaScript.tmLanguage | 52 +- .../typescript/syntaxes/TypeScript.tmLanguage | 52 +- .../syntaxes/TypeScriptReact.tmLanguage | 52 +- .../test/colorize-fixtures/test-issue11.ts | 17 + .../colorize-results/test-issue11_ts.json | 2884 +++++++++++++++++ 5 files changed, 3042 insertions(+), 15 deletions(-) create mode 100644 extensions/typescript/test/colorize-fixtures/test-issue11.ts create mode 100644 extensions/typescript/test/colorize-results/test-issue11_ts.json diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage b/extensions/javascript/syntaxes/JavaScript.tmLanguage index 0a59bccde92..514e2251788 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage @@ -1062,6 +1062,48 @@ + known-type-parameters + + begin + (<) + beginCaptures + + 1 + + name + meta.brace.angle.js + + + end + (?=$)|(>) + endCaptures + + 2 + + name + meta.brace.angle.js + + + name + meta.known.type.parameters.ts + patterns + + + match + \b(extends)\b + name + keyword.other.ts + + + include + #comment + + + include + #type + + + literal name @@ -1390,7 +1432,7 @@ include - #type-parameters + #know-type-parameters include @@ -1938,7 +1980,7 @@ include - #type-parameters + #known-type-parameters include @@ -1997,7 +2039,7 @@ type-declaration begin - \b(type)\b\s+([a-zA-Z_$][\w$]*)\s* + \b(type)\b\s+([a-zA-Z_$][\w$]*) beginCaptures 1 @@ -2019,7 +2061,7 @@ include - #type-parameters + #known-type-parameters include @@ -2130,7 +2172,7 @@ type-parameters begin - JAVASCRIPT_DOES_NOT_HAVE_TYPE_PARAMETERS_SO_NEVER_MATCH_PLEASE([a-zA-Z_$][\w$]*)?(<) + ([a-zA-Z_$][\w$]*)?\s*(<)(?=[^<]*(<[^<>]*>)*>\s*[(]) beginCaptures 1 diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage b/extensions/typescript/syntaxes/TypeScript.tmLanguage index 890815f0e05..25e00f25b29 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage @@ -695,6 +695,48 @@ name meta.indexer.parameter.ts + known-type-parameters + + begin + (<) + beginCaptures + + 1 + + name + meta.brace.angle.ts + + + end + (?=$)|(>) + endCaptures + + 2 + + name + meta.brace.angle.ts + + + name + meta.known.type.parameters.ts + patterns + + + match + \b(extends)\b + name + keyword.other.ts + + + include + #comment + + + include + #type + + + literal name @@ -1023,7 +1065,7 @@ include - #type-parameters + #known-type-parameters include @@ -1571,7 +1613,7 @@ include - #type-parameters + #known-type-parameters include @@ -1630,7 +1672,7 @@ type-declaration begin - \b(type)\b\s+([a-zA-Z_$][\w$]*)\s* + \b(type)\b\s+([a-zA-Z_$][\w$]*) beginCaptures 1 @@ -1652,7 +1694,7 @@ include - #type-parameters + #known-type-parameters include @@ -1763,7 +1805,7 @@ type-parameters begin - ([a-zA-Z_$][\w$]*)?(<) + ([a-zA-Z_$][\w$]*)?\s*(<)(?=[^<]*(<[^<>]*>)*>\s*[(]) beginCaptures 1 diff --git a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage index b9d77e3f52b..9cae064fd20 100644 --- a/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage +++ b/extensions/typescript/syntaxes/TypeScriptReact.tmLanguage @@ -1061,6 +1061,48 @@ + known-type-parameters + + begin + (<) + beginCaptures + + 1 + + name + meta.brace.angle.tsx + + + end + (?=$)|(>) + endCaptures + + 2 + + name + meta.brace.angle.tsx + + + name + meta.known.type.parameters.ts + patterns + + + match + \b(extends)\b + name + keyword.other.ts + + + include + #comment + + + include + #type + + + literal name @@ -1389,7 +1431,7 @@ include - #type-parameters + #know-type-parameters include @@ -1937,7 +1979,7 @@ include - #type-parameters + #known-type-parameters include @@ -1996,7 +2038,7 @@ type-declaration begin - \b(type)\b\s+([a-zA-Z_$][\w$]*)\s* + \b(type)\b\s+([a-zA-Z_$][\w$]*) beginCaptures 1 @@ -2018,7 +2060,7 @@ include - #type-parameters + #known-type-parameters include @@ -2129,7 +2171,7 @@ type-parameters begin - ([a-zA-Z_$][\w$]*)?(<) + ([a-zA-Z_$][\w$]*)?\s*(<)(?=[^<]*(<[^<>]*>)*>\s*[(]) beginCaptures 1 diff --git a/extensions/typescript/test/colorize-fixtures/test-issue11.ts b/extensions/typescript/test/colorize-fixtures/test-issue11.ts new file mode 100644 index 00000000000..8e17f24eaff --- /dev/null +++ b/extensions/typescript/test/colorize-fixtures/test-issue11.ts @@ -0,0 +1,17 @@ +let keyCode = 0; +if(!(keyCode === 8 || (keyCode>=48 && keyCode<=57))) {} +for (let i=0; i<5; i++) {} +for (var i=0; i<5; i++) {} +for (let i=0; i<5; i++) {} +for (; i<5;) {} +for (let i=0; 1+( i<<5 ) < 5;i++) {} +var p = 1?2:(3<4?5:6); +class A { } +class A1 string }> { } +class B { } +class C { } +function foo() { return 1;} +let x1: A<(param?: number) => void, B>; +let x2: A; +const t = 1 < (5 > 10 ? 1 : 2); +var f6 = 1 < foo(); \ No newline at end of file diff --git a/extensions/typescript/test/colorize-results/test-issue11_ts.json b/extensions/typescript/test/colorize-results/test-issue11_ts.json new file mode 100644 index 00000000000..56e2cdf7c2f --- /dev/null +++ b/extensions/typescript/test/colorize-results/test-issue11_ts.json @@ -0,0 +1,2884 @@ +[ + { + "c": "let", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "keyCode", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " = ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "0", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "if", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "!", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "keyCode ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "===", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "8", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "||", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "keyCode", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "48", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "&&", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " keyCode", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "57", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ")))", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "for", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "let", + "t": "storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "0", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "++", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "for", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "var", + "t": "storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "0", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "++", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "for", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "let", + "t": "storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "0", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "++", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "for", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "; i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "for", + "t": "control.keyword.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "let", + "t": "storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "0", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "; ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "+", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "(", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "5", + "t": "constant.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ";i", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "++", + "t": "arithmetic.keyword.operator.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": ")", + "t": "brace.meta.paren.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{}", + "t": "block.brace.curly.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "var", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "p", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " = ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "?", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "2", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ":", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.expr.meta.paren.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "3", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "<", + "t": "comparison.expr.keyword.meta.operator.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": "4", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": "?", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "5", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ":", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "6", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ")", + "t": "brace.expr.meta.paren.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "class", + "t": "declaration.meta.object.storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "A", + "t": "class.declaration.entity.meta.name.object.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.class rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.class rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.entity.name.class rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.brace.declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "X", + "t": "declaration.known.meta.name.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.name rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.name rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ", ", + "t": "declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "Y", + "t": "declaration.known.meta.name.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.name rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.name rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "body.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "class", + "t": "declaration.meta.object.storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "A1", + "t": "class.declaration.entity.meta.name.object.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.class rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.class rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.entity.name.class rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.brace.declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "T", + "t": "declaration.known.meta.name.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.name rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.name rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "extends", + "t": "declaration.keyword.known.meta.object.other.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "brace.curly.declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.field.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "a", + "t": "declaration.field.known.meta.object.parameters.ts.type.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ": ", + "t": "declaration.field.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "()", + "t": "brace.declaration.field.known.meta.object.parameters.paren.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.field.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=>", + "t": "declaration.field.keyword.known.meta.object.operator.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "declaration.field.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "string", + "t": "declaration.field.known.meta.object.parameters.primitive.support.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.type rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.type rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.field.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "brace.curly.declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "declaration.known.meta.object.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "body.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "class", + "t": "declaration.meta.object.storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "B", + "t": "class.declaration.entity.meta.name.object.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.class rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.class rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.entity.name.class rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "body.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "class", + "t": "declaration.meta.object.storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "C", + "t": "class.declaration.entity.meta.name.object.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.class rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.class rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.entity.name.class rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "body.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "body.brace.curly.declaration.meta.object.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "function", + "t": "function.meta.storage.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "foo", + "t": "entity.function.meta.name.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.entity.name.function rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.brace.function.meta.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "T", + "t": "function.meta.name.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.name rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.name rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "function.meta.parameters.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "()", + "t": "brace.function.meta.parameter.round.ts.type", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "{", + "t": "block.brace.curly.decl.function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "block.decl.function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "return", + "t": "block.control.decl.function.keyword.meta.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.control rgb(197, 134, 192)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.control rgb(175, 0, 219)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.control rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.control rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.control rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "block.decl.function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "block.constant.decl.function.meta.numeric.ts", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ";", + "t": "block.decl.function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "}", + "t": "block.brace.curly.decl.function.meta.ts", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "let", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "x1", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ": ", + "t": "annotation.expr.meta.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "A", + "t": "annotation.expr.meta.name.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.annotation.brace.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "annotation.cover.expr.known.meta.parameters.paren.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "param", + "t": "annotation.cover.expr.known.meta.name.parameters.paren.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "?: ", + "t": "annotation.cover.expr.known.meta.parameters.paren.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "number", + "t": "annotation.cover.expr.known.meta.parameters.paren.primitive.support.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ")", + "t": "annotation.cover.expr.known.meta.parameters.paren.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "=>", + "t": "annotation.expr.function.keyword.known.meta.operator.parameters.return.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "annotation.expr.function.known.meta.parameters.return.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "void", + "t": "annotation.expr.function.known.meta.parameters.primitive.return.support.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ", ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "B", + "t": "annotation.expr.known.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "let", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "x2", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ": ", + "t": "annotation.expr.meta.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "A", + "t": "annotation.expr.meta.name.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.annotation.brace.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "C", + "t": "annotation.expr.known.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "|", + "t": "annotation.expr.keyword.known.meta.operator.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "B", + "t": "annotation.expr.known.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ", ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "C", + "t": "annotation.expr.known.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " & ", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "B", + "t": "annotation.expr.known.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "annotation.expr.known.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.meta.type.annotation rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.meta.type.annotation rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "const", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "t", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " = ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.expr.keyword.meta.operator.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "(", + "t": "brace.expr.meta.paren.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "5", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "comparison.expr.keyword.meta.operator.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "10", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ? ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " : ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "2", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": ")", + "t": "brace.expr.meta.paren.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "var", + "t": "expr.meta.storage.ts.type.var", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.storage.type rgb(86, 156, 214)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.storage.type rgb(0, 0, 255)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.storage.type rgb(86, 156, 214)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.storage.type rgb(0, 0, 255)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.storage.type rgb(86, 156, 214)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "f6", + "t": "expr.meta.ts.var.var-single-variable.variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": " = ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "1", + "t": "constant.expr.meta.numeric.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.constant.numeric rgb(181, 206, 168)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.constant.numeric rgb(9, 136, 90)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.constant.numeric rgb(181, 206, 168)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.constant.numeric rgb(9, 136, 90)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.constant.numeric rgb(181, 206, 168)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "comparison.expr.keyword.meta.operator.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword.operator rgb(212, 212, 212)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword.operator rgb(0, 0, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword.operator rgb(212, 212, 212)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword.operator rgb(0, 0, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword.operator rgb(212, 212, 212)" + } + }, + { + "c": " ", + "t": "expr.meta.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "foo", + "t": "entity.expr.meta.name.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.entity.name.type rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.entity.name.type rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "<", + "t": "angle.brace.expr.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "string", + "t": "expr.meta.parameters.primitive.support.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.type rgb(78, 201, 176)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.type rgb(38, 127, 153)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ">", + "t": "expr.meta.parameters.ts.type.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": "()", + "t": "brace.expr.meta.paren.ts.var.var-single-variable", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + }, + { + "c": ";", + "t": "", + "r": { + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" + } + } +] \ No newline at end of file