提交 9b90c12a 编写于 作者: J Joao Moreno

remove extension quick open & status bar widget

上级 d5e4540b
......@@ -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<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(ExtensionsWorkbenchExtension);
Registry.as<IStatusbarRegistry>(StatusbarExtensions.Statusbar)
.registerStatusbarItem(new StatusbarItemDescriptor(ExtensionsStatusbarItem, StatusbarAlignment.LEFT,10000));
Registry.as<IOutputChannelRegistry>(OutputExtensions.OutputChannels)
.registerChannel(ExtensionsChannelId, ExtensionsLabel);
......
/*---------------------------------------------------------------------------------------------
* 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<any> {
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<any> {
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<IExtensionEntry> {
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<IExtensionEntry> {
public getAriaLabel(entry: IExtensionEntry): string {
return nls.localize('extensionAriaLabel', "{0}, {1}, extensions picker", entry.extension.displayName, entry.extension.description);
}
}
class Renderer implements IPagedRenderer<IExtensionEntry> {
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<IExtensionEntry> {
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<IExtensionEntry> {
public dataSource = new DataSource();
public renderer: IRenderer<IExtensionEntry>;
public accessibilityProvider: IAccessiblityProvider<IExtensionEntry> = 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<LocalExtensionsModel>;
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<IModel<IExtensionEntry>> {
if (!this.modelPromise) {
this.modelPromise = TPromise.join<any>([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<any>;
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<IModel<number>> {
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<IExtensionEntry>(
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<IExtensionEntry> {
public dataSource = new DataSource();
public accessibilityProvider: IAccessiblityProvider<IExtensionEntry> = new AccessibilityProvider();
public renderer: IRenderer<IExtensionEntry>;
public runner: IRunner<IExtensionEntry>;
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<OutdatedExtensionsModel>;
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<IModel<IExtensionEntry>> {
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<IExtensionEntry> {
public dataSource = new DataSource();
public renderer: IRenderer<IExtensionEntry>;
public runner: IRunner<IExtensionEntry>;
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<SuggestedExtensionsModel>;
constructor(
@IExtensionTipsService private extensionTipsService: IExtensionTipsService,
@IInstantiationService private instantiationService: IInstantiationService,
@ITelemetryService private telemetryService: ITelemetryService,
@IExtensionManagementService private extensionManagementService: IExtensionManagementService
) {
super();
}
getResults(input: string): TPromise<IModel<IExtensionEntry>> {
if (!this.modelPromise) {
this.telemetryService.publicLog('extensionRecommendations:open');
this.modelPromise = TPromise.join<any>([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 };
}
}
/*---------------------------------------------------------------------------------------------
* 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<void>(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<void> {
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
......@@ -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 = (<wbaregistry.IWorkbenchActionRegistry> platform.Registry.as(wbaregistry.Extensions.WorkbenchActions));
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ListExtensionsAction, ListExtensionsAction.ID, ListExtensionsAction.LABEL), 'Extensions: Show Installed Extensions', ExtensionsLabel);
(<IQuickOpenRegistry>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);
(<IQuickOpenRegistry>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);
(<IQuickOpenRegistry>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);
(<IQuickOpenRegistry>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 {
......
......@@ -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';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册