Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import * as types from 'vs/base/common/types';
import * as strings from 'vs/base/common/strings';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

export const Extensions = {
Configuration: 'base.contributions.configuration'
Expand Down Expand Up @@ -93,7 +94,7 @@ export interface IConfigurationNode {
}

export interface IDefaultConfigurationExtension {
id: string;
id: CanonicalExtensionIdentifier;
name: string;
defaults: { [key: string]: {} };
}
Expand Down
56 changes: 56 additions & 0 deletions src/vs/platform/extensions/common/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import * as strings from 'vs/base/common/strings';

export const MANIFEST_CACHE_FOLDER = 'CachedExtensions';
export const USER_MANIFEST_CACHE_FILE = 'user';
Expand All @@ -31,3 +32,58 @@ export function isUIExtension(manifest: IExtensionManifest, configurationService
default: return uiExtensions.has(extensionId) || !manifest.main;
}
}

/**
* **!Do not construct directly!**
*
* **!Only static methods because it gets serialized!**
*
* This represents the "canonical" version for an extension identifier. Extension ids
* have to be case-insensitive (due to the marketplace), but we must ensure case
* preservation because the extension API is already public at this time.
*
* For example, given an extension with the publisher `"Hello"` and the name `"World"`,
* its canonical extension identifier is `"Hello.World"`. This extension could be
* referenced in some other extension's dependencies using the string `"hello.world"`.
*
* To make matters more complicated, an extension can optionally have an UUID. When two
* extensions have the same UUID, they are considered equal even if their identifier is different.
*/
export class CanonicalExtensionIdentifier {
public readonly value: string;
private readonly _lower: string;

constructor(value: string) {
this.value = value;
this._lower = value.toLowerCase();
}

public static equals(a: CanonicalExtensionIdentifier | string | null | undefined, b: CanonicalExtensionIdentifier | string | null | undefined) {
if (typeof a === 'undefined' || a === null) {
return (typeof b === 'undefined' || b === null);
}
if (typeof b === 'undefined' || b === null) {
return false;
}
if (typeof a === 'string' || typeof b === 'string') {
// At least one of the arguments is an extension id in string form,
// so we have to use the string comparison which ignores case.
let aValue = (typeof a === 'string' ? a : a.value);
let bValue = (typeof b === 'string' ? b : b.value);
return strings.equalsIgnoreCase(aValue, bValue);
}

// Now we know both arguments are CanonicalExtensionIdentifier
return (a._lower === b._lower);
}

/**
* Gives the value by which to index (for equality).
*/
public static toKey(id: CanonicalExtensionIdentifier | string): string {
if (typeof id === 'string') {
return id.toLowerCase();
}
return id._lower;
}
}
3 changes: 2 additions & 1 deletion src/vs/platform/statusbar/common/statusbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

export const IStatusbarService = createDecorator<IStatusbarService>('statusbarService');

Expand Down Expand Up @@ -48,7 +49,7 @@ export interface IStatusbarEntry {
/**
* An optional extension ID if this entry is provided from an extension.
*/
readonly extensionId?: string;
readonly extensionId?: CanonicalExtensionIdentifier;

/**
* Wether to show a beak above the status bar entry.
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/api/browser/viewsContainersExtensionPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

export interface IUserFriendlyViewsContainerDescriptor {
id: string;
Expand Down Expand Up @@ -147,12 +148,12 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
containers.forEach(descriptor => {
const cssClass = `extensionViewlet-${descriptor.id}`;
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, order++, cssClass, extension.id);
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, order++, cssClass, extension.identifier);
});
return order;
}

private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor2, order: number, cssClass: string, extensionId: string): void {
private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor2, order: number, cssClass: string, extensionId: CanonicalExtensionIdentifier): void {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);
const id = descriptor.id;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/browser/viewsExtensionPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/parts/files/common/files';
import { VIEWLET_ID as SCM } from 'vs/workbench/parts/scm/common/scm';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/parts/debug/common/debug';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

interface IUserFriendlyViewDescriptor {
id: string;
Expand Down Expand Up @@ -136,7 +137,7 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
canToggleVisibility: true,
collapsed: this.showCollapsed(container),
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, container),
order: extension.description.id === container.extensionId ? index + 1 : void 0
order: CanonicalExtensionIdentifier.equals(extension.description.identifier, container.extensionId) ? index + 1 : void 0
};

viewIds.push(viewDescriptor.id);
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/api/electron-browser/mainThreadComments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { generateUuid } from 'vs/base/common/uuid';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ICommentsConfiguration } from 'vs/workbench/parts/comments/electron-browser/comments.contribution';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

export class MainThreadDocumentCommentProvider implements modes.DocumentCommentProvider {
private _proxy: ExtHostCommentsShape;
Expand Down Expand Up @@ -125,7 +126,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
}
}

$registerWorkspaceCommentProvider(handle: number, extensionId: string): void {
$registerWorkspaceCommentProvider(handle: number, extensionId: CanonicalExtensionIdentifier): void {
this._workspaceProviders.set(handle, undefined);

const providerId = generateUuid();
Expand Down Expand Up @@ -165,7 +166,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
}
*/
this._telemetryService.publicLog('comments:registerWorkspaceCommentProvider', {
extensionId: extensionId
extensionId: extensionId.value
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostC
import { IExtHostContext, MainContext, MainThreadExtensionServiceShape } from 'vs/workbench/api/node/extHost.protocol';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

@extHostNamedCustomer(MainContext.MainThreadExtensionService)
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {
Expand All @@ -30,13 +31,13 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
$localShowMessage(severity: Severity, msg: string): void {
this._extensionService._logOrShowMessage(severity, msg);
}
$onWillActivateExtension(extensionId: string): void {
$onWillActivateExtension(extensionId: CanonicalExtensionIdentifier): void {
this._extensionService._onWillActivateExtension(extensionId);
}
$onDidActivateExtension(extensionId: string, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void {
$onDidActivateExtension(extensionId: CanonicalExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void {
this._extensionService._onDidActivateExtension(extensionId, startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent);
}
$onExtensionRuntimeError(extensionId: string, data: SerializedError): void {
$onExtensionRuntimeError(extensionId: CanonicalExtensionIdentifier, data: SerializedError): void {
const error = new Error();
error.name = data.name;
error.message = data.message;
Expand All @@ -45,9 +46,9 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
console.error(`[${extensionId}]${error.message}`);
console.error(error.stack);
}
$onExtensionActivationFailed(extensionId: string): void {
$onExtensionActivationFailed(extensionId: CanonicalExtensionIdentifier): void {
}
$addMessage(extensionId: string, severity: Severity, message: string): void {
$addMessage(extensionId: CanonicalExtensionIdentifier, severity: Severity, message: string): void {
this._extensionService._addMessage(extensionId, severity, message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { Event } from 'vs/base/common/event';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { dispose } from 'vs/base/common/lifecycle';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

@extHostNamedCustomer(MainContext.MainThreadMessageService)
export class MainThreadMessageService implements MainThreadMessageServiceShape {
Expand Down Expand Up @@ -55,9 +56,9 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
}

class ManageExtensionAction extends Action {
constructor(id: string, label: string, commandService: ICommandService) {
super(id, label, undefined, true, () => {
return commandService.executeCommand('_extensions.manage', id);
constructor(id: CanonicalExtensionIdentifier, label: string, commandService: ICommandService) {
super(id.value, label, undefined, true, () => {
return commandService.executeCommand('_extensions.manage', id.value);
});
}
}
Expand All @@ -77,7 +78,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {

const secondaryActions: IAction[] = [];
if (extension && !extension.isUnderDevelopment) {
secondaryActions.push(new ManageExtensionAction(extension.id, nls.localize('manageExtension', "Manage Extension"), this._commandService));
secondaryActions.push(new ManageExtensionAction(extension.identifier, nls.localize('manageExtension', "Manage Extension"), this._commandService));
}

const messageHandle = this._notificationService.notify({
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/electron-browser/mainThreadStatusBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

@extHostNamedCustomer(MainContext.MainThreadStatusBar)
export class MainThreadStatusBar implements MainThreadStatusBarShape {
Expand All @@ -27,7 +28,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
}
}

$setEntry(id: number, extensionId: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {
$setEntry(id: number, extensionId: CanonicalExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void {

// Dispose any old
this.$dispose(id);
Expand Down
9 changes: 5 additions & 4 deletions src/vs/workbench/api/electron-browser/mainThreadUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { URI } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

class ExtensionUrlHandler implements IURLHandler {

constructor(
private readonly proxy: ExtHostUrlsShape,
private readonly handle: number,
readonly extensionId: string
readonly extensionId: CanonicalExtensionIdentifier
) { }

handleURL(uri: URI): Promise<boolean> {
if (uri.authority !== this.extensionId) {
if (!CanonicalExtensionIdentifier.equals(this.extensionId, uri.authority)) {
return Promise.resolve(false);
}

Expand All @@ -31,7 +32,7 @@ class ExtensionUrlHandler implements IURLHandler {
export class MainThreadUrls implements MainThreadUrlsShape {

private readonly proxy: ExtHostUrlsShape;
private handlers = new Map<number, { extensionId: string, disposable: IDisposable }>();
private handlers = new Map<number, { extensionId: CanonicalExtensionIdentifier, disposable: IDisposable }>();

constructor(
context: IExtHostContext,
Expand All @@ -41,7 +42,7 @@ export class MainThreadUrls implements MainThreadUrlsShape {
this.proxy = context.getProxy(ExtHostContext.ExtHostUrls);
}

$registerUriHandler(handle: number, extensionId: string): Promise<void> {
$registerUriHandler(handle: number, extensionId: CanonicalExtensionIdentifier): Promise<void> {
const handler = new ExtensionUrlHandler(this.proxy, handle, extensionId);
const disposable = this.urlService.registerHandler(handler);

Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/api/electron-browser/mainThreadWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as vscode from 'vscode';
import { extHostNamedCustomer } from './extHostCustomers';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { onUnexpectedError } from 'vs/base/common/errors';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

@extHostNamedCustomer(MainContext.MainThreadWebviews)
export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviver {
Expand Down Expand Up @@ -69,7 +70,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
title: string,
showOptions: { viewColumn: EditorViewColumn | null, preserveFocus: boolean },
options: WebviewInputOptions,
extensionId: string,
extensionId: CanonicalExtensionIdentifier,
extensionLocation: UriComponents
): void {
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
Expand All @@ -92,7 +93,7 @@ export class MainThreadWebviews implements MainThreadWebviewsShape, WebviewReviv
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId });
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value });
}

public $disposeWebview(handle: WebviewPanelHandle): void {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/api/electron-browser/mainThreadWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { IFolderQuery, IPatternInfo, ISearchConfiguration, ISearchProgressItem, ISearchService, QueryType, IFileQuery } from 'vs/platform/search/common/search';
Expand All @@ -24,6 +23,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common
import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape } from '../node/extHost.protocol';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { TextSearchComplete } from 'vscode';
import { CanonicalExtensionIdentifier } from 'vs/platform/extensions/common/extensions';

@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
Expand Down Expand Up @@ -246,7 +246,7 @@ CommandsRegistry.registerCommand('_workbench.enterWorkspace', async function (ac
if (disableExtensions && disableExtensions.length) {
const runningExtensions = await extensionService.getExtensions();
// If requested extension to disable is running, then reload window with given workspace
if (disableExtensions && runningExtensions.some(runningExtension => disableExtensions.some(id => areSameExtensions({ id }, { id: runningExtension.id })))) {
if (disableExtensions && runningExtensions.some(runningExtension => disableExtensions.some(id => CanonicalExtensionIdentifier.equals(runningExtension.identifier, id)))) {
return windowService.openWindow([URI.file(workspace.fsPath)], { args: { _: [], 'disable-extension': disableExtensions } });
}
}
Expand Down
Loading