Merge from vscode 81d7885dc2e9dc617e1522697a2966bc4025a45d (#5949)

* Merge from vscode 81d7885dc2e9dc617e1522697a2966bc4025a45d

* Fix vs unit tests and hygiene issue

* Fix strict null check issue
This commit is contained in:
Chris LaFreniere
2019-06-10 18:27:09 -07:00
committed by GitHub
parent ff38bc8143
commit d15a3fcc98
926 changed files with 19529 additions and 11383 deletions

View File

@@ -255,7 +255,7 @@ export class ExtensionData implements IExtensionData {
toQuery.push(id);
}
}
const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: this.childrenExtensionIds, pageSize: this.childrenExtensionIds.length }, CancellationToken.None);
const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: toQuery, pageSize: toQuery.length }, CancellationToken.None);
result.push(...galleryResult.firstPage);
return result.map(extension => new ExtensionData(extension, this, this.getChildrenExtensionIds, this.extensionsWorkbenchService));
}

View File

@@ -7,7 +7,7 @@ import * as arrays from 'vs/base/common/arrays';
import { localize } from 'vs/nls';
import { Event } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, IExtensionIdentifier, EnablementState, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
@@ -22,9 +22,7 @@ export interface IExtensionStatus {
globallyEnabled: boolean;
}
export class KeymapExtensions implements IWorkbenchContribution {
private disposables: IDisposable[] = [];
export class KeymapExtensions extends Disposable implements IWorkbenchContribution {
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -34,13 +32,12 @@ export class KeymapExtensions implements IWorkbenchContribution {
@INotificationService private readonly notificationService: INotificationService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
) {
this.disposables.push(
lifecycleService.onShutdown(() => this.dispose()),
instantiationService.invokeFunction(onExtensionChanged)((identifiers => {
Promise.all(identifiers.map(identifier => this.checkForOtherKeymaps(identifier)))
.then(undefined, onUnexpectedError);
}))
);
super();
this._register(lifecycleService.onShutdown(() => this.dispose()));
this._register(instantiationService.invokeFunction(onExtensionChanged)((identifiers => {
Promise.all(identifiers.map(identifier => this.checkForOtherKeymaps(identifier)))
.then(undefined, onUnexpectedError);
})));
}
private checkForOtherKeymaps(extensionIdentifier: IExtensionIdentifier): Promise<void> {
@@ -87,10 +84,6 @@ export class KeymapExtensions implements IWorkbenchContribution {
}]
);
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
export function onExtensionChanged(accessor: ServicesAccessor): Event<IExtensionIdentifier[]> {

View File

@@ -13,7 +13,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { Cache, CacheResult } from 'vs/base/common/cache';
import { Action } from 'vs/base/common/actions';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle';
import { domEvent } from 'vs/base/browser/event';
import { append, $, addClass, removeClass, finalHandler, join, toggleClass, hide, show } from 'vs/base/browser/dom';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
@@ -89,9 +89,9 @@ function removeEmbeddedSVGs(documentContent: string): string {
return newDocument.documentElement.outerHTML;
}
class NavBar {
class NavBar extends Disposable {
private _onChange = new Emitter<{ id: string | null, focus: boolean }>();
private _onChange = this._register(new Emitter<{ id: string | null, focus: boolean }>());
get onChange(): Event<{ id: string | null, focus: boolean }> { return this._onChange.event; }
private currentId: string | null = null;
@@ -99,9 +99,10 @@ class NavBar {
private actionbar: ActionBar;
constructor(container: HTMLElement) {
super();
const element = append(container, $('.navbar'));
this.actions = [];
this.actionbar = new ActionBar(element, { animated: false });
this.actionbar = this._register(new ActionBar(element, { animated: false }));
}
push(id: string, label: string, tooltip: string): void {
@@ -132,10 +133,6 @@ class NavBar {
this.actions.forEach(a => a.enabled = a.id !== id);
return Promise.resolve(undefined);
}
dispose(): void {
dispose(this.actionbar);
}
}
const NavbarSection = {

View File

@@ -5,14 +5,11 @@
import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { append, $, addDisposableListener } from 'vs/base/browser/dom';
import { IStatusbarRegistry, StatusbarItemDescriptor, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { Registry } from 'vs/platform/registry/common/platform';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWindowsService } from 'vs/platform/windows/common/windows';
@@ -22,10 +19,11 @@ import product from 'vs/platform/product/node/product';
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<IExtensionHostProfileService>;
private readonly _onDidChangeState: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
@@ -38,6 +36,9 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private _profileSession: ProfileSession | null;
private _state: ProfileSessionState;
private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined;
private profilingStatusBarIndicatorLabelUpdater: IDisposable | undefined;
public get state() { return this._state; }
public get lastProfile() { return this._profile; }
@@ -46,12 +47,18 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
@IEditorService private readonly _editorService: IEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IWindowsService private readonly _windowsService: IWindowsService,
@IDialogService private readonly _dialogService: IDialogService
@IDialogService private readonly _dialogService: IDialogService,
@IStatusbarService private readonly _statusbarService: IStatusbarService,
) {
super();
this._profile = null;
this._profileSession = null;
this._setState(ProfileSessionState.None);
CommandsRegistry.registerCommand('workbench.action.extensionHostProfilder.stop', () => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
}
private _setState(state: ProfileSessionState): void {
@@ -61,17 +68,48 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
this._state = state;
if (this._state === ProfileSessionState.Running) {
ProfileExtHostStatusbarItem.instance.show(() => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
this.updateProfilingStatusBarIndicator(true);
} else if (this._state === ProfileSessionState.Stopping) {
ProfileExtHostStatusbarItem.instance.hide();
this.updateProfilingStatusBarIndicator(false);
}
this._onDidChangeState.fire(undefined);
}
private updateProfilingStatusBarIndicator(visible: boolean): void {
if (this.profilingStatusBarIndicatorLabelUpdater) {
this.profilingStatusBarIndicatorLabelUpdater.dispose();
this.profilingStatusBarIndicatorLabelUpdater = undefined;
}
if (visible) {
const indicator: IStatusbarEntry = {
text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"),
tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."),
command: 'workbench.action.extensionHostProfilder.stop'
};
const timeStarted = Date.now();
const handle = setInterval(() => {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), });
}
}, 1000);
this.profilingStatusBarIndicatorLabelUpdater = toDisposable(() => clearInterval(handle));
if (!this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, 'status.profiler', nls.localize('status.profiler', "Extension Profiler"), StatusbarAlignment.RIGHT);
} else {
this.profilingStatusBarIndicator.update(indicator);
}
} else {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.dispose();
this.profilingStatusBarIndicator = undefined;
}
}
}
public startProfiling(): Promise<any> | null {
if (this._state !== ProfileSessionState.None) {
return null;
@@ -134,76 +172,3 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
}
}
export class ProfileExtHostStatusbarItem implements IStatusbarItem {
public static instance: ProfileExtHostStatusbarItem;
private toDispose: IDisposable[];
private statusBarItem: HTMLElement;
private label: HTMLElement;
private timeStarted: number;
private labelUpdater: any;
private clickHandler: (() => void) | null;
constructor() {
ProfileExtHostStatusbarItem.instance = this;
this.toDispose = [];
this.timeStarted = 0;
}
public show(clickHandler: () => void) {
this.clickHandler = clickHandler;
if (this.timeStarted === 0) {
this.timeStarted = new Date().getTime();
this.statusBarItem.hidden = false;
this.labelUpdater = setInterval(() => {
this.updateLabel();
}, 1000);
this.updateLabel();
}
}
public hide() {
this.clickHandler = null;
this.statusBarItem.hidden = true;
this.timeStarted = 0;
clearInterval(this.labelUpdater);
this.labelUpdater = null;
}
public render(container: HTMLElement): IDisposable {
if (!this.statusBarItem && container) {
this.statusBarItem = append(container, $('.profileExtHost-statusbar-item'));
this.toDispose.push(addDisposableListener(this.statusBarItem, 'click', () => {
if (this.clickHandler) {
this.clickHandler();
}
}));
this.statusBarItem.title = nls.localize('selectAndStartDebug', "Click to stop profiling.");
const a = append(this.statusBarItem, $('a'));
append(a, $('.icon'));
this.label = append(a, $('span.label'));
this.updateLabel();
this.statusBarItem.hidden = true;
}
return this;
}
private updateLabel() {
let label = 'Profiling Extension Host';
if (this.timeStarted > 0) {
let secondsRecoreded = (new Date().getTime() - this.timeStarted) / 1000;
label = `Profiling Extension Host (${Math.round(secondsRecoreded)} sec)`;
}
this.label.textContent = label;
}
public dispose(): void {
this.toDispose = dispose(this.toDispose);
}
}
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(
new StatusbarItemDescriptor(ProfileExtHostStatusbarItem, StatusbarAlignment.RIGHT)
);

View File

@@ -11,7 +11,7 @@ import { match } from 'vs/base/common/glob';
import * as json from 'vs/base/common/json';
import {
IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ExtensionRecommendationReason, EXTENSION_IDENTIFIER_PATTERN,
IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource, InstallOperation
IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource, InstallOperation, ILocalExtension
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ITextModel } from 'vs/editor/common/model';
@@ -90,7 +90,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
public loadWorkspaceConfigPromise: Promise<void>;
private proactiveRecommendationsFetched: boolean = false;
private readonly _onRecommendationChange = new Emitter<RecommendationChangeNotification>();
private readonly _onRecommendationChange = this._register(new Emitter<RecommendationChangeNotification>());
onRecommendationChange: Event<RecommendationChangeNotification> = this._onRecommendationChange.event;
private sessionSeed: number;
@@ -597,8 +597,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
* or prompt to search the marketplace if it has extensions that can support the file type
*/
private promptFiletypeBasedRecommendations(model: ITextModel): void {
let hasSuggestion = false;
const uri = model.uri;
if (!uri || !this.fileService.canHandleResource(uri)) {
return;
@@ -612,231 +610,244 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
processedFileExtensions.push(fileExtension);
}
// re-schedule this bit of the operation to be off
// the critical path - in case glob-match is slow
setImmediate(() => {
let recommendationsToSuggest: string[] = [];
const now = Date.now();
forEach(this._availableRecommendations, entry => {
let { key: pattern, value: ids } = entry;
if (match(pattern, uri.path)) {
for (let id of ids) {
if (caseInsensitiveGet(product.extensionImportantTips, id)) {
recommendationsToSuggest.push(id);
}
const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] };
filedBasedRecommendation.recommendedTime = now;
if (!filedBasedRecommendation.sources.some(s => s instanceof URI && s.toString() === uri.toString())) {
filedBasedRecommendation.sources.push(uri);
}
this._fileBasedRecommendations[id.toLowerCase()] = filedBasedRecommendation;
}
}
});
this.storageService.store(
'extensionsAssistant/recommendations',
JSON.stringify(Object.keys(this._fileBasedRecommendations).reduce((result, key) => { result[key] = this._fileBasedRecommendations[key].recommendedTime; return result; }, {})),
StorageScope.GLOBAL
);
const config = this.configurationService.getValue<IExtensionsConfiguration>(ConfigurationKey);
if (config.ignoreRecommendations || config.showRecommendationsOnlyOnDemand) {
// re-schedule this bit of the operation to be off the critical path - in case glob-match is slow
setImmediate(async () => {
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
if (await this.promptRecommendedExtensionForFileType(model, installed)) {
return;
}
const importantRecommendationsIgnoreList = <string[]>JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]'));
recommendationsToSuggest = recommendationsToSuggest.filter(id => importantRecommendationsIgnoreList.indexOf(id) === -1 && this.isExtensionAllowedToBeRecommended(id));
if (fileExtension) {
fileExtension = fileExtension.substr(1); // Strip the dot
}
if (!fileExtension) {
return;
}
const importantTipsPromise = recommendationsToSuggest.length === 0 ? Promise.resolve(null) : this.extensionWorkbenchService.queryLocal().then(local => {
const localExtensions = local.map(e => e.identifier);
recommendationsToSuggest = recommendationsToSuggest.filter(id => localExtensions.every(local => !areSameExtensions(local, { id })));
if (!recommendationsToSuggest.length) {
return;
}
const id = recommendationsToSuggest[0];
const entry = caseInsensitiveGet(product.extensionImportantTips, id);
if (!entry) {
return;
}
const name = entry['name'];
await this.extensionService.whenInstalledExtensionsRegistered();
const mimeTypes = await guessMimeTypes(uri.fsPath);
if (mimeTypes.length !== 1 || mimeTypes[0] !== MIME_UNKNOWN) {
return;
}
// Indicates we have a suggested extension via the whitelist
hasSuggestion = true;
this.promptRecommendedExtensionForFileExtension(fileExtension, installed);
});
}
let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name);
// Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364
if (id === 'vscjava.vscode-java-pack') {
message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name);
}
const setIgnoreRecommendationsConfig = (configVal: boolean) => {
this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER);
if (configVal) {
const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore';
this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE);
private async promptRecommendedExtensionForFileType(model: ITextModel, installed: ILocalExtension[]): Promise<boolean> {
let recommendationsToSuggest: string[] = [];
const now = Date.now();
forEach(this._availableRecommendations, entry => {
let { key: pattern, value: ids } = entry;
if (match(pattern, model.uri.path)) {
for (let id of ids) {
if (caseInsensitiveGet(product.extensionImportantTips, id)) {
recommendationsToSuggest.push(id);
}
};
this.notificationService.prompt(Severity.Info, message,
[{
label: localize('install', 'Install'),
run: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name });
this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run();
}
}, {
label: localize('showRecommendations', "Show Recommendations"),
run: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name });
const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations"));
recommendationsAction.run();
recommendationsAction.dispose();
}
}, {
label: choiceNever,
isSecondary: true,
run: () => {
importantRecommendationsIgnoreList.push(id);
this.storageService.store(
'extensionsAssistant/importantRecommendationsIgnore',
JSON.stringify(importantRecommendationsIgnoreList),
StorageScope.GLOBAL
);
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name });
this.notificationService.prompt(
Severity.Info,
localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"),
[{
label: localize('ignoreAll', "Yes, Ignore All"),
run: () => setIgnoreRecommendationsConfig(true)
}, {
label: localize('no', "No"),
run: () => setIgnoreRecommendationsConfig(false)
}]
);
}
}],
{
sticky: true,
onCancel: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name });
}
const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] };
filedBasedRecommendation.recommendedTime = now;
if (!filedBasedRecommendation.sources.some(s => s instanceof URI && s.toString() === model.uri.toString())) {
filedBasedRecommendation.sources.push(model.uri);
}
);
});
const mimeTypesPromise = this.extensionService.whenInstalledExtensionsRegistered()
.then(() => {
return guessMimeTypes(uri.fsPath);
});
Promise.all([importantTipsPromise, mimeTypesPromise]).then(result => {
const fileExtensionSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get
('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]'));
const mimeTypes = result[1];
if (fileExtension) {
fileExtension = fileExtension.substr(1); // Strip the dot
this._fileBasedRecommendations[id.toLowerCase()] = filedBasedRecommendation;
}
}
});
if (hasSuggestion ||
!fileExtension ||
mimeTypes.length !== 1 ||
mimeTypes[0] !== MIME_UNKNOWN ||
fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1
) {
return;
}
this.storageService.store(
'extensionsAssistant/recommendations',
JSON.stringify(Object.keys(this._fileBasedRecommendations).reduce((result, key) => { result[key] = this._fileBasedRecommendations[key].recommendedTime; return result; }, {})),
StorageScope.GLOBAL
);
const lookup = product.extensionKeywords || {};
const keywords = lookup[fileExtension] || [];
this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }, CancellationToken.None).then(pager => {
if (!pager || !pager.firstPage || !pager.firstPage.length) {
return;
const config = this.configurationService.getValue<IExtensionsConfiguration>(ConfigurationKey);
if (config.ignoreRecommendations || config.showRecommendationsOnlyOnDemand) {
return false;
}
const importantRecommendationsIgnoreList = <string[]>JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]'));
const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set<string>());
recommendationsToSuggest = recommendationsToSuggest.filter(id => {
if (importantRecommendationsIgnoreList.indexOf(id) !== -1) {
return false;
}
if (!this.isExtensionAllowedToBeRecommended(id)) {
return false;
}
if (installedExtensionsIds.has(id.toLowerCase())) {
return false;
}
return true;
});
if (recommendationsToSuggest.length === 0) {
return false;
}
const id = recommendationsToSuggest[0];
const entry = caseInsensitiveGet(product.extensionImportantTips, id);
if (!entry) {
return false;
}
const name = entry['name'];
let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name);
// Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364
if (id === 'vscjava.vscode-java-pack') {
message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name);
}
const setIgnoreRecommendationsConfig = (configVal: boolean) => {
this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER);
if (configVal) {
const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore';
this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE);
}
};
this.notificationService.prompt(Severity.Info, message,
[{
label: localize('install', 'Install'),
run: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name });
this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run();
}
}, {
label: localize('showRecommendations', "Show Recommendations"),
run: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name });
const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations"));
recommendationsAction.run();
recommendationsAction.dispose();
}
}, {
label: choiceNever,
isSecondary: true,
run: () => {
importantRecommendationsIgnoreList.push(id);
this.storageService.store(
'extensionsAssistant/importantRecommendationsIgnore',
JSON.stringify(importantRecommendationsIgnoreList),
StorageScope.GLOBAL
);
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name });
this.notificationService.prompt(
Severity.Info,
localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension),
localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"),
[{
label: searchMarketplace,
run: () => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension: fileExtension });
this.viewletService.openViewlet('workbench.view.extensions', true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search(`ext:${fileExtension}`);
viewlet.focus();
});
}
label: localize('ignoreAll', "Yes, Ignore All"),
run: () => setIgnoreRecommendationsConfig(true)
}, {
label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension),
run: () => {
fileExtensionSuggestionIgnoreList.push(fileExtension);
this.storageService.store(
'extensionsAssistant/fileExtensionsSuggestionIgnore',
JSON.stringify(fileExtensionSuggestionIgnoreList),
StorageScope.GLOBAL
);
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension });
}
}],
{
sticky: true,
onCancel: () => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension });
}
}
label: localize('no', "No"),
run: () => setIgnoreRecommendationsConfig(false)
}]
);
});
});
});
}
}],
{
sticky: true,
onCancel: () => {
/* __GDPR__
"extensionRecommendations:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name });
}
}
);
return true;
}
private async promptRecommendedExtensionForFileExtension(fileExtension: string, installed: ILocalExtension[]): Promise<void> {
const fileExtensionSuggestionIgnoreList = <string[]>JSON.parse(this.storageService.get('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]'));
if (fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1) {
return;
}
const text = `ext:${fileExtension}`;
const pager = await this.extensionWorkbenchService.queryGallery({ text, pageSize: 100 }, CancellationToken.None);
if (pager.firstPage.length === 0) {
return;
}
const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set<string>());
if (pager.firstPage.some(e => installedExtensionsIds.has(e.identifier.id.toLowerCase()))) {
return;
}
this.notificationService.prompt(
Severity.Info,
localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension),
[{
label: searchMarketplace,
run: () => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension: fileExtension });
this.viewletService.openViewlet('workbench.view.extensions', true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search(`ext:${fileExtension}`);
viewlet.focus();
});
}
}, {
label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension),
run: () => {
fileExtensionSuggestionIgnoreList.push(fileExtension);
this.storageService.store(
'extensionsAssistant/fileExtensionsSuggestionIgnore',
JSON.stringify(fileExtensionSuggestionIgnoreList),
StorageScope.GLOBAL
);
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension });
}
}],
{
sticky: true,
onCancel: () => {
/* __GDPR__
"fileExtensionSuggestion:popup" : {
"userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension });
}
}
);
}
//#endregion
@@ -1001,8 +1012,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
}), StorageScope.WORKSPACE);
/* __GDPR__
"dynamicWorkspaceRecommendations" : {
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"cache" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
"cache" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
}
*/
this.telemetryService.publicLog('dynamicWorkspaceRecommendations', { count: this._dynamicWorkspaceRecommendations.length, cache: 0 });

View File

@@ -50,6 +50,7 @@ import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron
import { onUnexpectedError } from 'vs/base/common/errors';
import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
// Singletons
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
@@ -421,3 +422,34 @@ CommandsRegistry.registerCommand({
}
}
});
CommandsRegistry.registerCommand({
id: 'workbench.extensions.uninstallExtension',
description: {
description: localize('workbench.extensions.uninstallExtension.description', "Uninstall the given extension"),
args: [
{
name: localize('workbench.extensions.uninstallExtension.arg.name', "Id of the extension to uninstall"),
schema: {
'type': 'string'
}
}
]
},
handler: async (accessor, id: string) => {
if (!id) {
throw new Error(localize('id required', "Extension id required."));
}
const extensionManagementService = accessor.get(IExtensionManagementService);
try {
const installed = await extensionManagementService.getInstalled(ExtensionType.User);
const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id }));
if (!extensionToUninstall) {
return Promise.reject(new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id)));
}
await extensionManagementService.uninstall(extensionToUninstall, true);
} catch (e) {
onUnexpectedError(e);
}
}
});

View File

@@ -12,7 +12,7 @@ import { Event } from 'vs/base/common/event';
import * as json from 'vs/base/common/json';
import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { dispose, Disposable } from 'vs/base/common/lifecycle';
// {{SQL CARBON EDIT}}
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions';
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
@@ -58,10 +58,11 @@ import { coalesce } from 'vs/base/common/arrays';
import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ILabelService } from 'vs/platform/label/common/label';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IProductService } from 'vs/platform/product/common/product';
// {{SQL CARBON EDIT}}
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
@@ -151,7 +152,6 @@ export class InstallAction extends ExtensionAction {
private static readonly Class = 'extension-action prominent install';
private static readonly InstallingClass = 'extension-action install installing';
private disposables: IDisposable[] = [];
private _manifest: IExtensionManifest | null;
set manifest(manifest: IExtensionManifest) {
@@ -168,11 +168,12 @@ export class InstallAction extends ExtensionAction {
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
@ILabelService private readonly labelService: ILabelService
) {
super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false);
this.update();
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
}
update(): void {
@@ -197,7 +198,7 @@ export class InstallAction extends ExtensionAction {
this.tooltip = InstallAction.INSTALLING_LABEL;
} else {
if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) {
if (isUIExtension(this._manifest, this.configurationService)) {
if (isUIExtension(this._manifest, this.productService, this.configurationService)) {
this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`;
} else {
@@ -281,11 +282,6 @@ export class InstallAction extends ExtensionAction {
}
return null;
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class RemoteInstallAction extends ExtensionAction {
@@ -297,7 +293,6 @@ export class RemoteInstallAction extends ExtensionAction {
private static readonly InstallingClass = 'extension-action install installing';
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private installing: boolean = false;
constructor(
@@ -306,9 +301,10 @@ export class RemoteInstallAction extends ExtensionAction {
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
) {
super(`extensions.remoteinstall`, RemoteInstallAction.INSTALL_LABEL, RemoteInstallAction.Class, false);
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
this.updateLabel();
this.update();
}
@@ -341,7 +337,7 @@ export class RemoteInstallAction extends ExtensionAction {
// Installed User Extension
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
// Local Workspace Extension
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.configurationService))
&& this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService))
// Extension does not exist in remote
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
&& this.extensionsWorkbenchService.canInstall(this.extension)
@@ -365,11 +361,6 @@ export class RemoteInstallAction extends ExtensionAction {
}
}
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class LocalInstallAction extends ExtensionAction {
@@ -381,7 +372,6 @@ export class LocalInstallAction extends ExtensionAction {
private static readonly InstallingClass = 'extension-action install installing';
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private installing: boolean = false;
constructor(
@@ -390,9 +380,10 @@ export class LocalInstallAction extends ExtensionAction {
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
) {
super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false);
this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables);
this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
this.updateLabel();
this.update();
}
@@ -420,7 +411,7 @@ export class LocalInstallAction extends ExtensionAction {
// Installed User Extension
&& this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
// Remote UI or Language pack Extension
&& this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.configurationService))
&& this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.productService, this.configurationService))
// Extension does not exist in local
&& !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)
&& this.extensionsWorkbenchService.canInstall(this.extension)
@@ -444,11 +435,6 @@ export class LocalInstallAction extends ExtensionAction {
}
}
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class UninstallAction extends ExtensionAction {
@@ -483,6 +469,7 @@ export class UninstallAction extends ExtensionAction {
this.label = UninstallAction.UninstallLabel;
this.class = UninstallAction.UninstallClass;
this.tooltip = UninstallAction.UninstallLabel;
if (state !== ExtensionState.Installed) {
this.enabled = false;
@@ -512,16 +499,14 @@ export class CombinedInstallAction extends ExtensionAction {
private static readonly NoExtensionClass = 'extension-action prominent install no-extension';
private installAction: InstallAction;
private uninstallAction: UninstallAction;
private disposables: IDisposable[] = [];
constructor(
@IInstantiationService instantiationService: IInstantiationService
) {
super('extensions.combinedInstall', '', '', false);
this.installAction = instantiationService.createInstance(InstallAction);
this.uninstallAction = instantiationService.createInstance(UninstallAction);
this.disposables.push(this.installAction, this.uninstallAction);
this.installAction = this._register(instantiationService.createInstance(InstallAction));
this.uninstallAction = this._register(instantiationService.createInstance(UninstallAction));
this.update();
}
@@ -574,11 +559,6 @@ export class CombinedInstallAction extends ExtensionAction {
return Promise.resolve();
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class UpdateAction extends ExtensionAction {
@@ -688,8 +668,6 @@ export class ExtensionActionViewItem extends ActionViewItem {
export abstract class ExtensionDropDownAction extends ExtensionAction {
protected disposables: IDisposable[] = [];
constructor(
id: string,
label: string,
@@ -713,17 +691,10 @@ export abstract class ExtensionDropDownAction extends ExtensionAction {
}
return Promise.resolve();
}
dispose(): void {
dispose(this.disposables);
super.dispose();
}
}
export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
private disposables: IDisposable[] = [];
constructor(action: ExtensionDropDownAction,
tabOnlyOnFocus: boolean,
@IContextMenuService private readonly contextMenuService: IContextMenuService
@@ -752,11 +723,6 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem {
}
return actions.length ? actions.slice(0, actions.length - 1) : actions;
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class ManageExtensionAction extends ExtensionDropDownAction {
@@ -1208,8 +1174,6 @@ export class UpdateAllAction extends Action {
static readonly ID = 'workbench.extensions.action.updateAllExtensions';
static LABEL = localize('updateAll', "Update All Extensions");
private disposables: IDisposable[] = [];
constructor(
id = UpdateAllAction.ID,
label = UpdateAllAction.LABEL,
@@ -1220,7 +1184,7 @@ export class UpdateAllAction extends Action {
) {
super(id, label, '', false);
this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
this.update();
}
@@ -1243,11 +1207,6 @@ export class UpdateAllAction extends Action {
return promptDownloadManually(extension.gallery, localize('failedToUpdate', "Failed to update \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService);
});
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class ReloadAction extends ExtensionAction {
@@ -1256,7 +1215,6 @@ export class ReloadAction extends ExtensionAction {
private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`;
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private _runningExtensions: IExtensionDescription[] | null = null;
constructor(
@@ -1266,10 +1224,11 @@ export class ReloadAction extends ExtensionAction {
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
) {
super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false);
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
this.updateRunningExtensions();
}
@@ -1350,7 +1309,7 @@ export class ReloadAction extends ExtensionAction {
return;
}
if (this.workbenchEnvironmentService.configuration.remoteAuthority) {
const uiExtension = isUIExtension(this.extension.local.manifest, this.configurationService);
const uiExtension = isUIExtension(this.extension.local.manifest, this.productService, this.configurationService);
// Local Workspace Extension
if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) {
const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0];
@@ -1383,11 +1342,6 @@ export class ReloadAction extends ExtensionAction {
run(): Promise<any> {
return Promise.resolve(this.windowService.reloadWindow());
}
dispose(): void {
dispose(this.disposables);
super.dispose();
}
}
export class SetColorThemeAction extends ExtensionAction {
@@ -1399,7 +1353,6 @@ export class SetColorThemeAction extends ExtensionAction {
private static readonly EnabledClass = 'extension-action theme';
private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`;
private disposables: IDisposable[] = [];
constructor(
private readonly colorThemes: IColorTheme[],
@@ -1409,7 +1362,7 @@ export class SetColorThemeAction extends ExtensionAction {
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false);
Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this, this.disposables);
this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this));
this.update();
}
@@ -1455,11 +1408,6 @@ export class SetColorThemeAction extends ExtensionAction {
const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
}
dispose() {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class SetFileIconThemeAction extends ExtensionAction {
@@ -1467,7 +1415,6 @@ export class SetFileIconThemeAction extends ExtensionAction {
private static readonly EnabledClass = 'extension-action theme';
private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`;
private disposables: IDisposable[] = [];
static getFileIconThemes(fileIconThemes: IFileIconTheme[], extension: IExtension): IFileIconTheme[] {
return fileIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id));
@@ -1481,7 +1428,7 @@ export class SetFileIconThemeAction extends ExtensionAction {
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false);
Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this, this.disposables);
this._register(Event.any<any>(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this));
this.update();
}
@@ -1527,11 +1474,6 @@ export class SetFileIconThemeAction extends ExtensionAction {
const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER;
return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target);
}
dispose() {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class OpenExtensionsViewletAction extends ShowViewletAction {
@@ -1629,8 +1571,6 @@ export class ClearExtensionsInputAction extends Action {
static readonly ID = 'workbench.extensions.action.clearExtensionsInput';
static LABEL = localize('clearExtensionsInput', "Clear Extensions Input");
private disposables: IDisposable[] = [];
constructor(
id: string,
label: string,
@@ -1640,7 +1580,7 @@ export class ClearExtensionsInputAction extends Action {
) {
super(id, label, 'clear-extensions', true);
this.onSearchChange(value);
onSearchChange(this.onSearchChange, this, this.disposables);
this._register(onSearchChange(this.onSearchChange, this));
}
private onSearchChange(value: string): void {
@@ -1655,10 +1595,6 @@ export class ClearExtensionsInputAction extends Action {
viewlet.focus();
});
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}
export class ShowBuiltInExtensionsAction extends Action {
@@ -1772,7 +1708,8 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
@IOpenerService private readonly openerService: IOpenerService,
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IProductService private readonly productService: IProductService,
) {
super(id, label, 'extension-action');
this.recommendations = recommendations;
@@ -1799,7 +1736,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action {
private async installExtension(extension: IExtension): Promise<void> {
try {
if (extension.local && extension.gallery) {
if (isUIExtension(extension.local.manifest, this.configurationService)) {
if (isUIExtension(extension.local.manifest, this.productService, this.configurationService)) {
await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery);
return;
} else if (this.extensionManagementServerService.remoteExtensionManagementServer) {
@@ -1862,7 +1799,6 @@ export class IgnoreExtensionRecommendationAction extends Action {
private static readonly Class = 'extension-action ignore';
private disposables: IDisposable[] = [];
extension: IExtension;
constructor(
@@ -1879,11 +1815,6 @@ export class IgnoreExtensionRecommendationAction extends Action {
this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, true);
return Promise.resolve();
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class UndoIgnoreExtensionRecommendationAction extends Action {
@@ -1892,7 +1823,6 @@ export class UndoIgnoreExtensionRecommendationAction extends Action {
private static readonly Class = 'extension-action undo-ignore';
private disposables: IDisposable[] = [];
extension: IExtension;
constructor(
@@ -1909,11 +1839,6 @@ export class UndoIgnoreExtensionRecommendationAction extends Action {
this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, false);
return Promise.resolve();
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
@@ -1989,7 +1914,6 @@ export class ShowAzureExtensionsAction extends Action {
export class ChangeSortAction extends Action {
private query: Query;
private disposables: IDisposable[] = [];
constructor(
id: string,
@@ -2006,7 +1930,7 @@ export class ChangeSortAction extends Action {
this.query = Query.parse('');
this.enabled = false;
onSearchChange(this.onSearchChange, this, this.disposables);
this._register(onSearchChange(this.onSearchChange, this));
}
private onSearchChange(value: string): void {
@@ -2311,7 +2235,6 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi
static readonly ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions';
static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)");
private disposables: IDisposable[] = [];
constructor(
id: string,
@@ -2324,7 +2247,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi
@ITextModelService textModelResolverService: ITextModelService
) {
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
this.contextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables);
this._register(this.contextService.onDidChangeWorkbenchState(() => this.update(), this));
this.update();
}
@@ -2341,11 +2264,6 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi
}
return Promise.resolve();
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction {
@@ -2353,7 +2271,6 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac
static readonly ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions';
static LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)");
private disposables: IDisposable[] = [];
constructor(
id: string,
@@ -2367,7 +2284,7 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService);
this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables);
this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this));
this.update();
}
@@ -2386,11 +2303,6 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac
return null;
});
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction {
@@ -2679,7 +2591,6 @@ export class DisabledLabelAction extends ExtensionAction {
private static readonly Class = 'disable-status';
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private _runningExtensions: IExtensionDescription[] | null = null;
constructor(
@@ -2688,8 +2599,8 @@ export class DisabledLabelAction extends ExtensionAction {
@IExtensionService private readonly extensionService: IExtensionService,
) {
super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false);
warningAction.onDidChange(() => this.update(), this, this.disposables);
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
this._register(warningAction.onDidChange(() => this.update(), this));
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
this.updateRunningExtensions();
}
@@ -2722,11 +2633,6 @@ export class DisabledLabelAction extends ExtensionAction {
run(): Promise<any> {
return Promise.resolve(null);
}
dispose(): void {
dispose(this.disposables);
super.dispose();
}
}
export class SystemDisabledWarningAction extends ExtensionAction {
@@ -2736,20 +2642,20 @@ export class SystemDisabledWarningAction extends ExtensionAction {
private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} info`;
updateWhenCounterExtensionChanges: boolean = true;
private disposables: IDisposable[] = [];
private _runningExtensions: IExtensionDescription[] | null = null;
constructor(
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
@ILabelService private readonly labelService: ILabelService,
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionService private readonly extensionService: IExtensionService,
) {
super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false);
this.labelService.onDidChangeFormatters(() => this.update(), this, this.disposables);
this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables);
this._register(this.labelService.onDidChangeFormatters(() => this.update(), this));
this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this));
this.updateRunningExtensions();
this.update();
}
@@ -2785,7 +2691,7 @@ export class SystemDisabledWarningAction extends ExtensionAction {
const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null;
const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
const localExtensionServer = localExtension ? localExtension.server : null;
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
@@ -2797,7 +2703,7 @@ export class SystemDisabledWarningAction extends ExtensionAction {
return;
}
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) {
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) {
if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) {
this.class = `${SystemDisabledWarningAction.INFO_CLASS}`;
this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer));
@@ -2820,11 +2726,6 @@ export class SystemDisabledWarningAction extends ExtensionAction {
run(): Promise<any> {
return Promise.resolve(null);
}
dispose(): void {
dispose(this.disposables);
super.dispose();
}
}
export class DisableAllAction extends Action {
@@ -2832,7 +2733,6 @@ export class DisableAllAction extends Action {
static readonly ID = 'workbench.extensions.action.disableAll';
static LABEL = localize('disableAll', "Disable All Installed Extensions");
private disposables: IDisposable[] = [];
constructor(
id: string = DisableAllAction.ID, label: string = DisableAllAction.LABEL,
@@ -2841,7 +2741,7 @@ export class DisableAllAction extends Action {
) {
super(id, label);
this.update();
this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
}
private update(): void {
@@ -2851,11 +2751,6 @@ export class DisableAllAction extends Action {
run(): Promise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.Disabled);
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class DisableAllWorkpsaceAction extends Action {
@@ -2863,7 +2758,6 @@ export class DisableAllWorkpsaceAction extends Action {
static readonly ID = 'workbench.extensions.action.disableAllWorkspace';
static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace");
private disposables: IDisposable[] = [];
constructor(
id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL,
@@ -2872,8 +2766,8 @@ export class DisableAllWorkpsaceAction extends Action {
) {
super(id, label);
this.update();
this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables);
this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables);
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this));
this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this));
}
private update(): void {
@@ -2883,11 +2777,6 @@ export class DisableAllWorkpsaceAction extends Action {
run(): Promise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.WorkspaceDisabled);
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class EnableAllAction extends Action {
@@ -2895,7 +2784,6 @@ export class EnableAllAction extends Action {
static readonly ID = 'workbench.extensions.action.enableAll';
static LABEL = localize('enableAll', "Enable All Extensions");
private disposables: IDisposable[] = [];
constructor(
id: string = EnableAllAction.ID, label: string = EnableAllAction.LABEL,
@@ -2904,7 +2792,7 @@ export class EnableAllAction extends Action {
) {
super(id, label);
this.update();
this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update()));
this._register(this.extensionsWorkbenchService.onChange(() => this.update()));
}
private update(): void {
@@ -2914,11 +2802,6 @@ export class EnableAllAction extends Action {
run(): Promise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.Enabled);
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class EnableAllWorkpsaceAction extends Action {
@@ -2926,7 +2809,6 @@ export class EnableAllWorkpsaceAction extends Action {
static readonly ID = 'workbench.extensions.action.enableAllWorkspace';
static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace");
private disposables: IDisposable[] = [];
constructor(
id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL,
@@ -2936,8 +2818,8 @@ export class EnableAllWorkpsaceAction extends Action {
) {
super(id, label);
this.update();
this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables);
this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables);
this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this));
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this));
}
private update(): void {
@@ -2947,11 +2829,6 @@ export class EnableAllWorkpsaceAction extends Action {
run(): Promise<any> {
return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.WorkspaceEnabled);
}
dispose(): void {
super.dispose();
this.disposables = dispose(this.disposables);
}
}
export class OpenExtensionsFolderAction extends Action {

View File

@@ -5,7 +5,7 @@
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { localize } from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { timeout } from 'vs/base/common/async';
@@ -17,7 +17,7 @@ export class ExtensionActivationProgress implements IWorkbenchContribution {
constructor(
@IExtensionService extensionService: IExtensionService,
@IProgressService2 progressService: IProgressService2,
@IProgressService progressService: IProgressService,
@ILogService logService: ILogService,
) {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { append, $, addClass, removeClass, toggleClass } from 'vs/base/browser/dom';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
import { Action } from 'vs/base/common/actions';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -118,11 +118,11 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, disabledLabelAction]);
actionbar.push(actions, actionOptions);
const disposables = [...actions, ...widgets, actionbar, extensionContainers];
const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers);
return {
// {{SQL CARBON EDIT}}
root, element, icon, name, /*installCount, ratings,*/ author, description, disposables, actionbar,
root, element, icon, name, /*installCount, ratings,*/ author, description, disposables: [disposables], actionbar,
extensionDisposables: [],
set extension(extension: IExtension) {
extensionContainers.extension = extension;

View File

@@ -28,7 +28,7 @@ import { IExtensionManagementService, IExtensionManagementServerService, IExtens
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews';
import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import Severity from 'vs/base/common/severity';
import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
@@ -58,6 +58,7 @@ import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { ILabelService } from 'vs/platform/label/common/label';
import { MementoObject } from 'vs/workbench/common/memento';
interface SearchInputEvent extends Event {
target: HTMLInputElement;
@@ -343,12 +344,12 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private primaryActions: IAction[];
private secondaryActions: IAction[] | null;
private disposables: IDisposable[] = [];
private searchViewletState: object;
private readonly searchViewletState: MementoObject;
constructor(
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITelemetryService telemetryService: ITelemetryService,
@IProgressService2 private readonly progressService: IProgressService2,
@IProgressService private readonly progressService: IProgressService,
@IInstantiationService instantiationService: IInstantiationService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { dispose, Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { Event, Emitter } from 'vs/base/common/event';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors';
import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging';
import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
@@ -24,14 +24,13 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { distinct, coalesce } from 'vs/base/common/arrays';
@@ -43,9 +42,10 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { IAction } from 'vs/base/common/actions';
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import product from 'vs/platform/product/node/product';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil';
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IProductService } from 'vs/platform/product/common/product';
import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon';
class ExtensionsViewState extends Disposable implements IExtensionsViewState {
@@ -68,9 +68,13 @@ export interface ExtensionsListViewOptions extends IViewletViewOptions {
server?: IExtensionManagementServer;
}
class ExtensionListViewWarning extends Error { }
export class ExtensionsListView extends ViewletPanel {
private readonly server: IExtensionManagementServer | undefined;
private messageContainer: HTMLElement;
private messageSeverityIcon: HTMLElement;
private messageBox: HTMLElement;
private extensionsList: HTMLElement;
private badge: CountBadge;
@@ -89,13 +93,13 @@ export class ExtensionsListView extends ViewletPanel {
@IExtensionsWorkbenchService protected extensionsWorkbenchService: IExtensionsWorkbenchService,
@IEditorService private readonly editorService: IEditorService,
@IExtensionTipsService protected tipsService: IExtensionTipsService,
@IModeService private readonly modeService: IModeService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
@IExperimentService private readonly experimentService: IExperimentService,
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService
@IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService,
@IProductService protected readonly productService: IProductService,
) {
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
this.server = options.server;
@@ -110,12 +114,14 @@ export class ExtensionsListView extends ViewletPanel {
this.badgeContainer = append(container, $('.count-badge-wrapper'));
this.badge = new CountBadge(this.badgeContainer);
this.disposables.push(attachBadgeStyler(this.badge, this.themeService));
this._register(attachBadgeStyler(this.badge, this.themeService));
}
renderBody(container: HTMLElement): void {
this.extensionsList = append(container, $('.extensions-list'));
this.messageBox = append(container, $('.message'));
this.messageContainer = append(container, $('.message-container'));
this.messageSeverityIcon = append(this.messageContainer, $(''));
this.messageBox = append(this.messageContainer, $('.message'));
const delegate = new Delegate();
const extensionsViewState = new ExtensionsViewState();
const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState);
@@ -125,20 +131,20 @@ export class ExtensionsListView extends ViewletPanel {
setRowLineHeight: false,
horizontalScrolling: false
}) as WorkbenchPagedList<IExtension>;
this.list.onContextMenu(e => this.onContextMenu(e), this, this.disposables);
this.list.onFocusChange(e => extensionsViewState.onFocusChange(coalesce(e.elements)), this, this.disposables);
this.disposables.push(this.list);
this.disposables.push(extensionsViewState);
this._register(this.list.onContextMenu(e => this.onContextMenu(e), this));
this._register(this.list.onFocusChange(e => extensionsViewState.onFocusChange(coalesce(e.elements)), this));
this._register(this.list);
this._register(extensionsViewState);
Event.chain(this.list.onOpen)
this._register(Event.chain(this.list.onOpen)
.map(e => e.elements[0])
.filter(e => !!e)
.on(this.openExtension, this, this.disposables);
.on(this.openExtension, this));
Event.chain(this.list.onPin)
this._register(Event.chain(this.list.onPin)
.map(e => e.elements[0])
.filter(e => !!e)
.on(this.pin, this, this.disposables);
.on(this.pin, this));
}
protected layoutBody(height: number, width: number): void {
@@ -176,12 +182,11 @@ export class ExtensionsListView extends ViewletPanel {
};
const errorCallback = (e: Error) => {
const errorCallback = (e: any) => {
const model = new PagedModel([]);
if (!isPromiseCanceledError(e)) {
this.queryRequest = null;
console.warn('Error querying extensions gallery', e);
this.setModel(model, true);
this.setModel(model, e);
}
return this.list ? this.list.model : model;
};
@@ -236,7 +241,11 @@ export class ExtensionsListView extends ViewletPanel {
if (ExtensionsListView.isLocalExtensionsQuery(query.value) || /@builtin/.test(query.value)) {
return this.queryLocal(query, options);
}
return this.queryGallery(query, options, token);
return this.queryGallery(query, options, token)
.then(null, e => {
console.warn('Error querying extensions gallery', getErrorMessage(e));
return Promise.reject(new ExtensionListViewWarning(localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later.")));
});
}
private async queryByIds(ids: string[], options: IQueryOptions, token: CancellationToken): Promise<IPagedModel<IExtension>> {
@@ -431,29 +440,11 @@ export class ExtensionsListView extends ViewletPanel {
return this.getCuratedModel(query, options, token);
}
let text = query.value;
const extensionRegex = /\bext:([^\s]+)\b/g;
const text = query.value;
if (extensionRegex.test(query.value)) {
text = query.value.replace(extensionRegex, (m, ext) => {
// Get curated keywords
const lookup = product.extensionKeywords || {};
const keywords = lookup[ext] || [];
// Get mode name
const modeId = this.modeService.getModeIdByFilepathOrFirstLine(`.${ext}`);
const languageName = modeId && this.modeService.getLanguageName(modeId);
const languageTag = languageName ? ` tag:"${languageName}"` : '';
// Construct a rich query
return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag} tag:"${ext}"`;
});
if (text !== query.value) {
options = assign(options, { text: text.substr(0, 350), source: 'file-extension-tags' });
return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager));
}
if (/\bext:([^\s]+)\b/g.test(text)) {
options = assign(options, { text, source: 'file-extension-tags' });
return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager));
}
let preferredResults: string[] = [];
@@ -733,28 +724,36 @@ export class ExtensionsListView extends ViewletPanel {
});
}
private setModel(model: IPagedModel<IExtension>, isGalleryError?: boolean) {
private setModel(model: IPagedModel<IExtension>, error?: any) {
if (this.list) {
this.list.model = new DelayedPagedModel(model);
this.list.scrollTop = 0;
const count = this.count();
toggleClass(this.extensionsList, 'hidden', count === 0);
toggleClass(this.messageBox, 'hidden', count > 0);
toggleClass(this.messageContainer, 'hidden', count > 0);
this.badge.setCount(count);
if (count === 0 && this.isBodyVisible()) {
this.messageBox.textContent = isGalleryError ? localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later.") : localize('no extensions found', "No extensions found.");
if (isGalleryError) {
alert(this.messageBox.textContent);
if (error) {
if (error instanceof ExtensionListViewWarning) {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning);
this.messageBox.textContent = getErrorMessage(error);
} else {
this.messageSeverityIcon.className = SeverityIcon.className(Severity.Error);
this.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error));
}
} else {
this.messageSeverityIcon.className = '';
this.messageBox.textContent = localize('no extensions found', "No extensions found.");
}
} else {
this.messageBox.textContent = '';
alert(this.messageBox.textContent);
}
}
}
private openExtension(extension: IExtension): void {
extension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0] || extension;
this.extensionsWorkbenchService.open(extension).then(undefined, err => this.onError(err));
}
@@ -806,7 +805,6 @@ export class ExtensionsListView extends ViewletPanel {
this.queryRequest.request.cancel();
this.queryRequest = null;
}
this.disposables = dispose(this.disposables);
this.list = null;
}
@@ -886,18 +884,18 @@ export class ServerExtensionsView extends ExtensionsListView {
@IExtensionService extensionService: IExtensionService,
@IEditorService editorService: IEditorService,
@IExtensionTipsService tipsService: IExtensionTipsService,
@IModeService modeService: IModeService,
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IExperimentService experimentService: IExperimentService,
@IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService,
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
@IProductService productService: IProductService,
) {
options.server = server;
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, modeService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService);
this.disposables.push(onDidChangeTitle(title => this.updateTitle(title)));
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService);
this._register(onDidChangeTitle(title => this.updateTitle(title)));
}
async show(query: string): Promise<IPagedModel<IExtension>> {
@@ -950,7 +948,7 @@ export class DefaultRecommendedExtensionsView extends ExtensionsListView {
renderBody(container: HTMLElement): void {
super.renderBody(container);
this.disposables.push(this.tipsService.onRecommendationChange(() => {
this._register(this.tipsService.onRecommendationChange(() => {
this.show('');
}));
}
@@ -975,7 +973,7 @@ export class RecommendedExtensionsView extends ExtensionsListView {
renderBody(container: HTMLElement): void {
super.renderBody(container);
this.disposables.push(this.tipsService.onRecommendationChange(() => {
this._register(this.tipsService.onRecommendationChange(() => {
this.show('');
}));
}
@@ -993,9 +991,9 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
renderBody(container: HTMLElement): void {
super.renderBody(container);
this.disposables.push(this.tipsService.onRecommendationChange(() => this.update()));
this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.setRecommendationsToInstall()));
this.disposables.push(this.contextService.onDidChangeWorkbenchState(() => this.update()));
this._register(this.tipsService.onRecommendationChange(() => this.update()));
this._register(this.extensionsWorkbenchService.onChange(() => this.setRecommendationsToInstall()));
this._register(this.contextService.onDidChangeWorkbenchState(() => this.update()));
}
renderHeader(container: HTMLElement): void {
@@ -1004,21 +1002,19 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
const listActionBar = $('.list-actionbar-container');
container.insertBefore(listActionBar, this.badgeContainer);
const actionbar = new ActionBar(listActionBar, {
const actionbar = this._register(new ActionBar(listActionBar, {
animated: false
});
}));
actionbar.onDidRun(({ error }) => error && this.notificationService.error(error));
this.installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, []);
const configureWorkspaceFolderAction = this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL);
this.installAllAction = this._register(this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, []));
const configureWorkspaceFolderAction = this._register(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL));
this.installAllAction.class = 'octicon octicon-cloud-download';
configureWorkspaceFolderAction.class = 'octicon octicon-pencil';
actionbar.push([this.installAllAction], { icon: true, label: false });
actionbar.push([configureWorkspaceFolderAction], { icon: true, label: false });
this.disposables.push(...[this.installAllAction, configureWorkspaceFolderAction, actionbar]);
}
async show(query: string): Promise<IPagedModel<IExtension>> {
@@ -1045,7 +1041,7 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView {
if (!extension || !extension.local || extension.state !== ExtensionState.Installed) {
return true;
}
return isUIExtension(extension.local.manifest, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer;
return isUIExtension(extension.local.manifest, this.productService, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer;
}));
}
}

View File

@@ -81,22 +81,6 @@
width: 10px;
}
.monaco-action-bar .action-item .action-label.system-disable.warning.icon {
background: url('status-warning.svg') center center no-repeat;
}
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.warning.icon {
background: url('status-warning-inverse.svg') center center no-repeat;
}
.monaco-action-bar .action-item .action-label.system-disable.info.icon {
background: url('status-info.svg') center center no-repeat;
}
.vs-dark .monaco-action-bar .action-item .action-label.system-disable.info.icon {
background: url('status-info-inverse.svg') center center no-repeat;
}
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.extension-status-label,
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.disable-status,
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status {

View File

@@ -38,7 +38,7 @@
}
.extensions-viewlet > .extensions .extensions-list.hidden,
.extensions-viewlet > .extensions .message.hidden {
.extensions-viewlet > .extensions .message-container.hidden {
display: none;
visibility: hidden;
}
@@ -51,9 +51,14 @@
flex: 1;
}
.extensions-viewlet > .extensions .message {
.extensions-viewlet > .extensions .message-container {
padding: 5px 9px 5px 16px;
cursor: default;
display: flex;
}
.extensions-viewlet > .extensions .message-container .message {
padding-left: 5px;
}
.extensions-viewlet > .extensions .monaco-list-row > .bookmark {

View File

@@ -36,20 +36,3 @@
.runtime-extensions-editor .monaco-action-bar .actions-container {
justify-content: left;
}
.monaco-workbench .part.statusbar .profileExtHost-statusbar-item .icon {
background: url('profile-stop.svg') no-repeat;
display: inline-block;
padding-right: 2px;
padding-bottom: 2px;
width: 16px;
height: 16px;
vertical-align: middle;
animation:fade 1000ms infinite;
}
@keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.5; }
to { opacity: 1.0; }
}

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#1E1E1E"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#252526"/></svg>

Before

Width:  |  Height:  |  Size: 356 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><circle cx="8.5" cy="7.5" r="5.5" fill="#F6F6F6"/><path d="M8.5 3C6.015 3 4 5.015 4 7.5S6.015 12 8.5 12 13 9.985 13 7.5 10.985 3 8.5 3zm.5 8H8V6h1v5zm0-6H8V4h1v1z" fill="#1BA1E2"/><path d="M8 6h1v5H8V6zm0-2v1h1V4H8z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 353 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" height="16" width="16"><path fill="#1E1E1E" d="M7.5 2L2 12l2 2h9l2-2L9.5 2z"/><path d="M9 3H8l-4.5 9 1 1h8l1-1L9 3zm0 9H8v-1h1v1zm0-2H8V6h1v4z" fill="#fc0"/><path d="M9 10H8V6h1v4zm0 1H8v1h1v-1z"/></svg>

Before

Width:  |  Height:  |  Size: 263 B

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16" height="16" width="16"><path fill="#F6F6F6" d="M7.5 2L2 12l2 2h9l2-2L9.5 2z"/><path d="M9 3H8l-4.5 9 1 1h8l1-1L9 3zm0 9H8v-1h1v1zm0-2H8V6h1v4z" fill="#fc0"/><path d="M9 10H8V6h1v4zm0 1H8v1h1v-1z"/></svg>

Before

Width:  |  Height:  |  Size: 297 B

View File

@@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { index, distinct } from 'vs/base/common/arrays';
import { ThrottledDelayer } from 'vs/base/common/async';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
// {{SQL CARBON EDIT}}
@@ -17,7 +17,7 @@ import {
IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions,
InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, INSTALL_ERROR_INCOMPATIBLE
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWindowService } from 'vs/platform/windows/common/windows';
@@ -29,13 +29,14 @@ import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import product from 'vs/platform/product/node/product';
import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { INotificationService } from 'vs/platform/notification/common/notification';
import * as resources from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { IModeService } from 'vs/editor/common/services/modeService';
// {{SQL CARBON EDIT}}
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
@@ -497,7 +498,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
private readonly remoteExtensions: Extensions | null;
private syncDelayer: ThrottledDelayer<void>;
private autoUpdateDelayer: ThrottledDelayer<void>;
private disposables: IDisposable[] = [];
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
@@ -516,10 +516,11 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService,
@IWindowService private readonly windowService: IWindowService,
@ILogService private readonly logService: ILogService,
@IProgressService2 private readonly progressService: IProgressService2,
@IProgressService private readonly progressService: IProgressService,
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
@IStorageService private readonly storageService: IStorageService,
@IFileService private readonly fileService: IFileService
@IFileService private readonly fileService: IFileService,
@IModeService private readonly modeService: IModeService
) {
super();
this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer));
@@ -536,7 +537,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
urlService.registerHandler(this);
this.configurationService.onDidChangeConfiguration(e => {
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
// {{SQL CARBON EDIT}}
// if (this.isAutoUpdateEnabled()) {
@@ -548,7 +549,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
this.checkForUpdates();
}
}
}, this, this.disposables);
}, this));
this.queryLocal().then(() => {
this.resetIgnoreAutoUpdateExtensions();
@@ -602,6 +603,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
queryGallery(arg1: any, arg2?: any): Promise<IPager<IExtension>> {
const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1;
const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2;
options.text = options.text ? this.resolveQueryText(options.text) : options.text;
return this.extensionService.getExtensionsReport()
.then(report => {
const maliciousSet = getMaliciousExtensionsSet(report);
@@ -618,6 +620,27 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
});
}
private resolveQueryText(text: string): string {
const extensionRegex = /\bext:([^\s]+)\b/g;
if (extensionRegex.test(text)) {
text = text.replace(extensionRegex, (m, ext) => {
// Get curated keywords
const lookup = product.extensionKeywords || {};
const keywords = lookup[ext] || [];
// Get mode name
const modeId = this.modeService.getModeIdByFilepathOrFirstLine(`.${ext}`);
const languageName = modeId && this.modeService.getLanguageName(modeId);
const languageTag = languageName ? ` tag:"${languageName}"` : '';
// Construct a rich query
return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag} tag:"${ext}"`;
});
}
return text.substr(0, 350);
}
open(extension: IExtension, sideByside: boolean = false): Promise<any> {
return Promise.resolve(this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), undefined, sideByside ? SIDE_GROUP : ACTIVE_GROUP));
}
@@ -1116,7 +1139,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}
dispose(): void {
super.dispose();
this.syncDelayer.cancel();
this.disposables = dispose(this.disposables);
}
}

View File

@@ -113,7 +113,7 @@ suite('ExtensionsListView Tests', () => {
instantiationService.stubPromise(IExtensionTipsService, 'getOtherRecommendations', [
{ extensionId: otherRecommendationA.identifier.id }
]);
const reasons = {};
const reasons: { [key: string]: any } = {};
reasons[workspaceRecommendationA.identifier.id] = { reasonId: ExtensionRecommendationReason.Workspace };
reasons[workspaceRecommendationB.identifier.id] = { reasonId: ExtensionRecommendationReason.Workspace };
reasons[fileBasedRecommendationA.identifier.id] = { reasonId: ExtensionRecommendationReason.File };

View File

@@ -30,8 +30,8 @@ import { TestContextService, TestWindowService, TestSharedProcessService } from
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IProgressService2 } from 'vs/platform/progress/common/progress';
import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2';
import { IProgressService } from 'vs/platform/progress/common/progress';
import { ProgressService } from 'vs/workbench/services/progress/browser/progressService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { URLService } from 'vs/platform/url/common/urlService';
import { URI } from 'vs/base/common/uri';
@@ -61,7 +61,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
instantiationService.stub(ITelemetryService, NullTelemetryService);
instantiationService.stub(ILogService, NullLogService);
instantiationService.stub(IWindowService, TestWindowService);
instantiationService.stub(IProgressService2, ProgressService2);
instantiationService.stub(IProgressService, ProgressService);
instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService);
instantiationService.stub(IURLService, URLService);