Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568

This commit is contained in:
ADS Merger
2020-04-30 00:53:43 +00:00
parent 87e5239713
commit 93f35ca321
413 changed files with 7190 additions and 8756 deletions

View File

@@ -4,10 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IActivityService, IBadge } from 'vs/workbench/services/activity/common/activity';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IActivityService, IActivity } from 'vs/workbench/services/activity/common/activity';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity';
export class ActivityService implements IActivityService {
@@ -15,16 +17,27 @@ export class ActivityService implements IActivityService {
constructor(
@IPanelService private readonly panelService: IPanelService,
@IActivityBarService private readonly activityBarService: IActivityBarService
@IActivityBarService private readonly activityBarService: IActivityBarService,
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
) { }
showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable {
if (this.panelService.getPanels().filter(p => p.id === compositeOrActionId).length) {
return this.panelService.showActivity(compositeOrActionId, badge, clazz);
showViewContainerActivity(viewContainerId: string, { badge, clazz, priority }: IActivity): IDisposable {
const viewContainer = this.viewDescriptorService.getViewContainerById(viewContainerId);
if (viewContainer) {
const location = this.viewDescriptorService.getViewContainerLocation(viewContainer);
switch (location) {
case ViewContainerLocation.Panel:
return this.panelService.showActivity(viewContainer.id, badge, clazz);
case ViewContainerLocation.Sidebar:
return this.activityBarService.showActivity(viewContainer.id, badge, clazz, priority);
}
}
return Disposable.None;
}
return this.activityBarService.showActivity(compositeOrActionId, badge, clazz, priority);
showGlobalActivity({ badge, clazz, priority }: IActivity): IDisposable {
return this.activityBarService.showActivity(GLOBAL_ACTIVITY_ID, badge, clazz, priority);
}
}
registerSingleton(IActivityService, ActivityService, true);
registerSingleton(IActivityService, ActivityService, true);

View File

@@ -3,8 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { Event } from 'vs/base/common/event';
export interface IActivity {
readonly badge: IBadge;
readonly clazz?: string;
readonly priority?: number;
}
export const IActivityService = createDecorator<IActivityService>('activityService');
@@ -13,9 +21,47 @@ export interface IActivityService {
_serviceBrand: undefined;
/**
* Show activity in the panel for the given panel or in the activitybar for the given viewlet or global action.
* Show activity for the given view container
*/
showActivity(compositeOrActionId: string, badge: IBadge, clazz?: string, priority?: number): IDisposable;
showViewContainerActivity(viewContainerId: string, badge: IActivity): IDisposable;
/**
* Show global activity
*/
showGlobalActivity(activity: IActivity): IDisposable;
}
export class ViewContaierActivityByView extends Disposable {
private activity: IActivity | undefined = undefined;
private activityDisposable: IDisposable = Disposable.None;
constructor(
private readonly viewId: string,
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
@IActivityService private readonly activityService: IActivityService,
) {
super();
this._register(Event.filter(this.viewDescriptorService.onDidChangeContainer, e => e.views.some(view => view.id === viewId))(() => this.update()));
this._register(Event.filter(this.viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === viewId))(() => this.update()));
}
setActivity(activity: IActivity): void {
this.activity = activity;
this.update();
}
private update(): void {
this.activityDisposable.dispose();
const container = this.viewDescriptorService.getViewContainerByViewId(this.viewId);
if (container && this.activity) {
this.activityDisposable = this.activityService.showViewContainerActivity(container.id, this.activity);
}
}
dispose() {
this.activityDisposable.dispose();
}
}
export interface IBadge {

View File

@@ -225,7 +225,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe
return normalizeDriveLetter(getFolderUri().fsPath);
case 'cwd':
return (folderUri ? normalizeDriveLetter(getFolderUri().fsPath) : process.cwd());
return ((folderUri || argument) ? normalizeDriveLetter(getFolderUri().fsPath) : process.cwd());
case 'workspaceRootFolderName':
case 'workspaceFolderBasename':
@@ -249,14 +249,14 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe
return getFilePath();
case 'relativeFile':
if (folderUri) {
if (folderUri || argument) {
return paths.normalize(paths.relative(getFolderUri().fsPath, getFilePath()));
}
return getFilePath();
case 'relativeFileDirname':
let dirname = paths.dirname(getFilePath());
if (folderUri) {
const dirname = paths.dirname(getFilePath());
if (folderUri || argument) {
return paths.normalize(paths.relative(getFolderUri().fsPath, dirname));
}
return dirname;

View File

@@ -11,7 +11,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { BaseConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Workspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { TestEditorService } from 'vs/workbench/test/browser/workbenchTestServices';
import { TestWindowConfiguration } from 'vs/workbench/test/electron-browser/workbenchTestServices';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
@@ -23,6 +23,7 @@ import { EditorType } from 'vs/editor/common/editorCommon';
import { Selection } from 'vs/editor/common/core/selection';
import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
const mockLineNumber = 10;
class TestEditorServiceWithActiveEditor extends TestEditorService {
@@ -36,6 +37,13 @@ class TestEditorServiceWithActiveEditor extends TestEditorService {
}
};
}
get activeEditor(): any {
return {
get resource(): any {
return uri.parse('file:///VSCode/workspaceLocation/file');
}
};
}
}
class TestConfigurationResolverService extends BaseConfigurationResolverService {
@@ -48,6 +56,7 @@ suite('Configuration Resolver Service', () => {
let environmentService: MockWorkbenchEnvironmentService;
let mockCommandService: MockCommandService;
let editorService: TestEditorServiceWithActiveEditor;
let containingWorkspace: Workspace;
let workspace: IWorkspaceFolder;
let quickInputService: MockQuickInputService;
@@ -56,13 +65,9 @@ suite('Configuration Resolver Service', () => {
editorService = new TestEditorServiceWithActiveEditor();
quickInputService = new MockQuickInputService();
environmentService = new MockWorkbenchEnvironmentService(envVariables);
workspace = {
uri: uri.parse('file:///VSCode/workspaceLocation'),
name: 'hey',
index: 0,
toResource: (path: string) => uri.file(path)
};
configurationResolverService = new TestConfigurationResolverService({ getExecPath: () => undefined }, environmentService.userEnv, editorService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(), quickInputService);
containingWorkspace = testWorkspace(uri.parse('file:///VSCode/workspaceLocation'));
workspace = containingWorkspace.folders[0];
configurationResolverService = new TestConfigurationResolverService({ getExecPath: () => undefined }, environmentService.userEnv, editorService, new MockInputsConfigurationService(), mockCommandService, new TestContextService(containingWorkspace), quickInputService);
});
teardown(() => {
@@ -77,6 +82,34 @@ suite('Configuration Resolver Service', () => {
}
});
test('workspace folder with argument', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder:workspaceLocation} xyz'), 'abc \\VSCode\\workspaceLocation xyz');
} else {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder:workspaceLocation} xyz'), 'abc /VSCode/workspaceLocation xyz');
}
});
test('workspace folder with invalid argument', () => {
assert.throws(() => configurationResolverService!.resolve(workspace, 'abc ${workspaceFolder:invalidLocation} xyz'));
});
test('workspace folder with undefined workspace folder', () => {
assert.throws(() => configurationResolverService!.resolve(undefined, 'abc ${workspaceFolder} xyz'));
});
test('workspace folder with argument and undefined workspace folder', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService!.resolve(undefined, 'abc ${workspaceFolder:workspaceLocation} xyz'), 'abc \\VSCode\\workspaceLocation xyz');
} else {
assert.strictEqual(configurationResolverService!.resolve(undefined, 'abc ${workspaceFolder:workspaceLocation} xyz'), 'abc /VSCode/workspaceLocation xyz');
}
});
test('workspace folder with invalid argument and undefined workspace folder', () => {
assert.throws(() => configurationResolverService!.resolve(undefined, 'abc ${workspaceFolder:invalidLocation} xyz'));
});
test('workspace root folder name', () => {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${workspaceRootFolderName} xyz'), 'abc workspaceLocation xyz');
});
@@ -85,6 +118,34 @@ suite('Configuration Resolver Service', () => {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${mockLineNumber} xyz`);
});
test('relative file', () => {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${relativeFile} xyz'), 'abc file xyz');
});
test('relative file with argument', () => {
assert.strictEqual(configurationResolverService!.resolve(workspace, 'abc ${relativeFile:workspaceLocation} xyz'), 'abc file xyz');
});
test('relative file with invalid argument', () => {
assert.throws(() => configurationResolverService!.resolve(workspace, 'abc ${relativeFile:invalidLocation} xyz'));
});
test('relative file with undefined workspace folder', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService!.resolve(undefined, 'abc ${relativeFile} xyz'), 'abc \\VSCode\\workspaceLocation\\file xyz');
} else {
assert.strictEqual(configurationResolverService!.resolve(undefined, 'abc ${relativeFile} xyz'), 'abc /VSCode/workspaceLocation/file xyz');
}
});
test('relative file with argument and undefined workspace folder', () => {
assert.strictEqual(configurationResolverService!.resolve(undefined, 'abc ${relativeFile:workspaceLocation} xyz'), 'abc file xyz');
});
test('relative file with invalid argument and undefined workspace folder', () => {
assert.throws(() => configurationResolverService!.resolve(undefined, 'abc ${relativeFile:invalidLocation} xyz'));
});
test('substitute many', () => {
if (platform.isWindows) {
assert.strictEqual(configurationResolverService!.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), '\\VSCode\\workspaceLocation - \\VSCode\\workspaceLocation');

View File

@@ -34,7 +34,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
import { timeout } from 'vs/base/common/async';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { indexOfPath } from 'vs/base/common/extpath';
import { DEFAULT_CUSTOM_EDITOR, updateViewTypeSchema, editorAssociationsConfigurationNode } from 'vs/workbench/services/editor/browser/editorAssociationsSetting';
import { DEFAULT_CUSTOM_EDITOR, updateViewTypeSchema, editorAssociationsConfigurationNode } from 'vs/workbench/services/editor/common/editorAssociationsSetting';
import { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
type CachedEditorInput = ResourceEditorInput | IFileEditorInput | UntitledTextEditorInput;
@@ -480,10 +480,10 @@ export class EditorService extends Disposable implements EditorServiceImpl {
return toDisposable(() => remove());
}
getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] {
getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][] {
const ret = [];
for (const handler of this.openEditorHandlers) {
const handlers = handler.getEditorOverrides ? handler.getEditorOverrides(editorInput, options, group).map(val => { return [handler, val] as [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry]; }) : [];
const handlers = handler.getEditorOverrides ? handler.getEditorOverrides(resource, options, group).map(val => { return [handler, val] as [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry]; }) : [];
ret.push(...handlers);
}
@@ -1165,8 +1165,8 @@ export class DelegatingEditorService implements IEditorService {
@IEditorService private editorService: EditorService
) { }
getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined) {
return [];
getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined) {
return this.editorService.getEditorOverrides(resource, options, group);
}
openEditor(editor: IEditorInput, options?: IEditorOptions | ITextEditorOptions, group?: OpenInEditorGroup): Promise<IEditorPane | undefined>;

View File

@@ -10,6 +10,7 @@ import { Event } from 'vs/base/common/event';
import { IEditor, IDiffEditor } from 'vs/editor/common/editorCommon';
import { IEditorGroup, IEditorReplacement } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
export const IEditorService = createDecorator<IEditorService>('editorService');
@@ -35,7 +36,7 @@ export interface IOpenEditorOverrideEntry {
export interface IOpenEditorOverrideHandler {
open(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup, id?: string): IOpenEditorOverride | undefined;
getEditorOverrides?(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[];
getEditorOverrides?(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): IOpenEditorOverrideEntry[];
}
export interface IOpenEditorOverride {
@@ -224,7 +225,7 @@ export interface IEditorService {
/**
* Get all available editor overrides for the editor input.
*/
getEditorOverrides(editorInput: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][];
getEditorOverrides(resource: URI, options: IEditorOptions | undefined, group: IEditorGroup | undefined): [IOpenEditorOverrideHandler, IOpenEditorOverrideEntry][];
/**
* Allows to override the opening of editors by installing a handler that will

View File

@@ -254,4 +254,6 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
return extensionHostDebugEnvironment;
}
get skipReleaseNotes(): boolean { return false; }
}

View File

@@ -28,4 +28,6 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
readonly webviewExternalEndpoint: string;
readonly webviewResourceRoot: string;
readonly webviewCspSource: string;
readonly skipReleaseNotes: boolean;
}

View File

@@ -55,6 +55,9 @@ export class NativeWorkbenchEnvironmentService extends EnvironmentService implem
@memoize
get extHostLogsPath(): URI { return URI.file(join(this.logsPath, `exthost${this.configuration.windowId}`)); }
@memoize
get skipReleaseNotes(): boolean { return !!this.args['skip-release-notes']; }
constructor(
readonly configuration: INativeEnvironmentConfiguration,
execPath: string

View File

@@ -8,21 +8,35 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedPr
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionTipsService, IExecutableBasedExtensionTip, IWorkspaceTips, IConfigBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri';
import { ExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService';
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/productService';
import { IRequestService } from 'vs/platform/request/common/request';
import { ILogService } from 'vs/platform/log/common/log';
import { Schemas } from 'vs/base/common/network';
class NativeExtensionTipsService implements IExtensionTipsService {
class NativeExtensionTipsService extends ExtensionTipsService implements IExtensionTipsService {
_serviceBrand: any;
private readonly channel: IChannel;
constructor(
@IFileService fileService: IFileService,
@IProductService productService: IProductService,
@IRequestService requestService: IRequestService,
@ILogService logService: ILogService,
@ISharedProcessService sharedProcessService: ISharedProcessService
) {
super(fileService, productService, requestService, logService);
this.channel = sharedProcessService.getChannel('extensionTipsService');
}
getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]> {
return this.channel.call<IConfigBasedExtensionTip[]>('getConfigBasedTips', [folder]);
if (folder.scheme === Schemas.file) {
return this.channel.call<IConfigBasedExtensionTip[]>('getConfigBasedTips', [folder]);
}
return super.getConfigBasedTips(folder);
}
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {

View File

@@ -19,6 +19,8 @@ import { localize } from 'vs/nls';
import { IProductService } from 'vs/platform/product/common/productService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { generateUuid } from 'vs/base/common/uuid';
import { joinPath } from 'vs/base/common/resources';
export class RemoteExtensionManagementChannelClient extends ExtensionManagementChannelClient {
@@ -84,7 +86,8 @@ export class RemoteExtensionManagementChannelClient extends ExtensionManagementC
}
private async downloadAndInstall(extension: IGalleryExtension, installed: ILocalExtension[]): Promise<ILocalExtension> {
const location = await this.galleryService.download(extension, URI.file(tmpdir()), installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install);
const location = joinPath(URI.file(tmpdir()), generateUuid());
await this.galleryService.download(extension, location, installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install);
return super.install(location);
}

View File

@@ -117,14 +117,34 @@ export class BrowserHostService extends Disposable implements IHostService {
const openable = toOpen[i];
openable.label = openable.label || this.getRecentLabel(openable);
// selectively copy payload: for now only extension debugging properties are considered
const originalPayload = this.workspaceProvider.payload;
let newPayload: Array<unknown> | undefined = undefined;
if (originalPayload && Array.isArray(originalPayload)) {
for (let pair of originalPayload) {
if (Array.isArray(pair) && pair.length === 2) {
switch (pair[0]) {
case 'extensionDevelopmentPath':
case 'debugId':
case 'inspect-brk-extensions':
if (!newPayload) {
newPayload = new Array();
}
newPayload.push(pair);
break;
}
}
}
}
// Folder
if (isFolderToOpen(openable)) {
this.workspaceProvider.open({ folderUri: openable.folderUri }, { reuse: this.shouldReuse(options, false /* no file */) });
this.workspaceProvider.open({ folderUri: openable.folderUri }, { reuse: this.shouldReuse(options, false /* no file */), payload: newPayload });
}
// Workspace
else if (isWorkspaceToOpen(openable)) {
this.workspaceProvider.open({ workspaceUri: openable.workspaceUri }, { reuse: this.shouldReuse(options, false /* no file */) });
this.workspaceProvider.open({ workspaceUri: openable.workspaceUri }, { reuse: this.shouldReuse(options, false /* no file */), payload: newPayload });
}
// File

View File

@@ -31,12 +31,16 @@ export class KeybindingIO {
if (quotedSerializedWhen.length > 0) {
out.write(`${quotedSerializeCommand},`);
out.writeLine();
out.write(` "when": ${quotedSerializedWhen} `);
out.write(` "when": ${quotedSerializedWhen}`);
} else {
out.write(`${quotedSerializeCommand} `);
out.write(`${quotedSerializeCommand}`);
}
// out.write(String(item.weight1 + '-' + item.weight2));
out.write('}');
if (item.commandArgs) {
out.write(',');
out.writeLine();
out.write(` "args": ${JSON.stringify(item.commandArgs)}`);
}
out.write(' }');
}
public static readUserKeybindingItem(input: IUserFriendlyKeybinding): IUserKeybindingItem {

View File

@@ -59,6 +59,7 @@ export interface ISetting {
overrides?: ISetting[];
overrideOf?: ISetting;
deprecationMessage?: string;
deprecationMessageIsMarkdown?: boolean;
scope?: ConfigurationScope;
type?: string | string[];

View File

@@ -639,7 +639,8 @@ export class DefaultSettings extends Disposable {
tags: prop.tags,
disallowSyncIgnore: prop.disallowSyncIgnore,
extensionInfo: extensionInfo,
deprecationMessage: prop.deprecationMessage,
deprecationMessage: prop.markdownDeprecationMessage || prop.deprecationMessage,
deprecationMessageIsMarkdown: !!prop.markdownDeprecationMessage,
validator: createValidator(prop)
});
}

View File

@@ -75,7 +75,7 @@ export class ProgressService extends Disposable implements IProgressService {
// Window progress without command can be shown as silent notification
// which will first appear in the status bar and can then be brought to
// the front when clicking.
return this.withNotificationProgress({ ...options, silent: true, location: ProgressLocation.Notification }, task, onDidCancel);
return this.withNotificationProgress({ delay: 150 /* default for ProgressLocation.Window */, ...options, silent: true, location: ProgressLocation.Notification }, task, onDidCancel);
case ProgressLocation.Explorer:
return this.withViewletProgress('workbench.view.explorer', task, { ...options, location });
case ProgressLocation.Scm:
@@ -440,7 +440,7 @@ export class ProgressService extends Disposable implements IProgressService {
let activityProgress: IDisposable;
let delayHandle: any = setTimeout(() => {
delayHandle = undefined;
const handle = this.activityService.showActivity(viewletId, new ProgressBadge(() => ''), 'progress-badge', 100);
const handle = this.activityService.showViewContainerActivity(viewletId, { badge: new ProgressBadge(() => ''), clazz: 'progress-badge', priority: 100 });
const startTimeVisible = Date.now();
const minTimeVisible = 300;
activityProgress = {

View File

@@ -30,7 +30,7 @@ class TestViewlet implements IViewlet {
getControl(): IEditorControl { return null!; }
focus(): void { }
getOptimalWidth(): number { return 10; }
openView(id: string, focus?: boolean): IView { return null!; }
openView<T extends IView>(id: string, focus?: boolean): T | undefined { return undefined; }
getViewPaneContainer(): IViewPaneContainer { return null!; }
saveState(): void { }
}

View File

@@ -50,7 +50,8 @@ export class TelemetryService extends Disposable implements ITelemetryService {
if (!!productService.enableTelemetry) {
const config: ITelemetryServiceConfig = {
appender: combinedAppender(new WebTelemetryAppender(logService, remoteAgentService), new LogAppender(logService)),
commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.remoteAuthority, environmentService.options && environmentService.options.resolveCommonTelemetryProperties)
commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.remoteAuthority, environmentService.options && environmentService.options.resolveCommonTelemetryProperties),
sendErrorTelemetry: false,
};
this.impl = this._register(new BaseTelemetryService(config, configurationService));
@@ -75,6 +76,14 @@ export class TelemetryService extends Disposable implements ITelemetryService {
return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths);
}
publicLogError(errorEventName: string, data?: ITelemetryData): Promise<void> {
return this.impl.publicLog(errorEventName, data);
}
publicLogError2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
return this.publicLogError(eventName, data as ITelemetryData);
}
getTelemetryInfo(): Promise<ITelemetryInfo> {
return this.impl.getTelemetryInfo();
}

View File

@@ -40,7 +40,8 @@ export class TelemetryService extends Disposable implements ITelemetryService {
const config: ITelemetryServiceConfig = {
appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)),
commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, productService.msftInternalDomains, environmentService.installSourcePath, environmentService.configuration.remoteAuthority),
piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot]
piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot],
sendErrorTelemetry: true
};
this.impl = this._register(new BaseTelemetryService(config, configurationService));
@@ -65,6 +66,15 @@ export class TelemetryService extends Disposable implements ITelemetryService {
return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths);
}
publicLogError(errorEventName: string, data?: ITelemetryData): Promise<void> {
return this.impl.publicLogError(errorEventName, data);
}
publicLogError2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
return this.publicLog(eventName, data as ITelemetryData);
}
getTelemetryInfo(): Promise<ITelemetryInfo> {
return this.impl.getTelemetryInfo();
}

View File

@@ -30,6 +30,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
export abstract class AbstractTextMateService extends Disposable implements ITextMateService {
public _serviceBrand: undefined;
@@ -41,6 +42,9 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
private readonly _createdModes: string[];
private readonly _encounteredLanguages: boolean[];
private _debugMode: boolean;
private _debugModePrintFunc: (str: string) => void;
private _grammarDefinitions: IValidGrammarDefinition[] | null;
private _grammarFactory: TMGrammarFactory | null;
private _tokenizersRegistrations: IDisposable[];
@@ -54,7 +58,8 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
@INotificationService private readonly _notificationService: INotificationService,
@ILogService private readonly _logService: ILogService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IStorageService private readonly _storageService: IStorageService
@IStorageService private readonly _storageService: IStorageService,
@IProgressService private readonly _progressService: IProgressService
) {
super();
this._styleElement = dom.createStyleSheet();
@@ -62,6 +67,9 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
this._createdModes = [];
this._encounteredLanguages = [];
this._debugMode = false;
this._debugModePrintFunc = () => { };
this._grammarDefinitions = null;
this._grammarFactory = null;
this._tokenizersRegistrations = [];
@@ -174,6 +182,46 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
});
}
public startDebugMode(printFn: (str: string) => void, onStop: () => void): void {
if (this._debugMode) {
this._notificationService.error(nls.localize('alreadyDebugging', "Already Logging."));
return;
}
this._debugModePrintFunc = printFn;
this._debugMode = true;
if (this._debugMode) {
this._progressService.withProgress(
{
location: ProgressLocation.Notification,
buttons: [nls.localize('stop', "Stop")]
},
(progress) => {
progress.report({
message: nls.localize('progress1', "Preparing to log TM Grammar parsing. Press Stop when finished.")
});
return this._getVSCodeOniguruma().then((vscodeOniguruma) => {
vscodeOniguruma.setDefaultDebugCall(true);
progress.report({
message: nls.localize('progress2', "Now logging TM Grammar parsing. Press Stop when finished.")
});
return new Promise<void>((resolve, reject) => { });
});
},
(choice) => {
this._getVSCodeOniguruma().then((vscodeOniguruma) => {
this._debugModePrintFunc = () => { };
this._debugMode = false;
vscodeOniguruma.setDefaultDebugCall(false);
onStop();
});
}
);
}
}
private _canCreateGrammarFactory(): boolean {
// Check if extension point is ready
return (this._grammarDefinitions ? true : false);
@@ -184,7 +232,11 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
return this._grammarFactory;
}
const vscodeTextmate = await this._loadVSCodeTextmate();
const [vscodeTextmate, vscodeOniguruma] = await Promise.all([import('vscode-textmate'), this._getVSCodeOniguruma()]);
const onigLib: Promise<IOnigLib> = Promise.resolve({
createOnigScanner: (sources: string[]) => vscodeOniguruma.createOnigScanner(sources),
createOnigString: (str: string) => vscodeOniguruma.createOnigString(str)
});
// Avoid duplicate instantiations
if (this._grammarFactory) {
@@ -195,7 +247,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
logTrace: (msg: string) => this._logService.trace(msg),
logError: (msg: string, err: any) => this._logService.error(msg, err),
readFile: (resource: URI) => this._extensionResourceLoaderService.readExtensionResource(resource)
}, this._grammarDefinitions || [], vscodeTextmate, this._loadOnigLib());
}, this._grammarDefinitions || [], vscodeTextmate, onigLib);
this._onDidCreateGrammarFactory(this._grammarDefinitions || []);
this._updateTheme(this._grammarFactory, this._themeService.getColorTheme(), true);
@@ -340,8 +392,27 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
protected _onDidDisposeGrammarFactory(): void {
}
protected abstract _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')>;
protected abstract _loadOnigLib(): Promise<IOnigLib> | undefined;
private _vscodeOniguruma: Promise<typeof import('vscode-oniguruma')> | null = null;
private _getVSCodeOniguruma(): Promise<typeof import('vscode-oniguruma')> {
if (!this._vscodeOniguruma) {
this._vscodeOniguruma = this._doGetVSCodeOniguruma();
}
return this._vscodeOniguruma;
}
private async _doGetVSCodeOniguruma(): Promise<typeof import('vscode-oniguruma')> {
const [vscodeOniguruma, wasm] = await Promise.all([import('vscode-oniguruma'), this._loadVSCodeOnigurumWASM()]);
const options = {
data: wasm,
print: (str: string) => {
this._debugModePrintFunc(str);
}
};
await vscodeOniguruma.loadWASM(options);
return vscodeOniguruma;
}
protected abstract _loadVSCodeOnigurumWASM(): Promise<Response | ArrayBuffer>;
}
const donotAskUpdateKey = 'editor.maxTokenizationLineLength.donotask';

View File

@@ -6,7 +6,6 @@
import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService';
import { IOnigLib } from 'vscode-textmate';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -14,6 +13,7 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { IProgressService } from 'vs/platform/progress/common/progress';
export class TextMateService extends AbstractTextMateService {
@@ -24,46 +24,20 @@ export class TextMateService extends AbstractTextMateService {
@INotificationService notificationService: INotificationService,
@ILogService logService: ILogService,
@IConfigurationService configurationService: IConfigurationService,
@IStorageService storageService: IStorageService
@IStorageService storageService: IStorageService,
@IProgressService progressService: IProgressService
) {
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService);
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService, progressService);
}
protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> {
return import('vscode-textmate');
protected async _loadVSCodeOnigurumWASM(): Promise<Response | ArrayBuffer> {
const wasmPath = require.toUrl('vscode-oniguruma/../onig.wasm');
const response = await fetch(wasmPath);
// Using the response directly only works if the server sets the MIME type 'application/wasm'.
// Otherwise, a TypeError is thrown when using the streaming compiler.
// We therefore use the non-streaming compiler :(.
return await response.arrayBuffer();
}
protected _loadOnigLib(): Promise<IOnigLib> | undefined {
return loadOnigasm();
}
}
let onigasmPromise: Promise<IOnigLib> | null = null;
async function loadOnigasm(): Promise<IOnigLib> {
if (!onigasmPromise) {
onigasmPromise = doLoadOnigasm();
}
return onigasmPromise;
}
async function doLoadOnigasm(): Promise<IOnigLib> {
const [wasmBytes, onigasm] = await Promise.all([
loadOnigasmWASM(),
import('onigasm-umd')
]);
await onigasm.loadWASM(wasmBytes);
return {
createOnigScanner(patterns: string[]) { return new onigasm.OnigScanner(patterns); },
createOnigString(s: string) { return new onigasm.OnigString(s); }
};
}
async function loadOnigasmWASM(): Promise<ArrayBuffer> {
const wasmPath = require.toUrl('onigasm-umd/../onigasm.wasm');
const response = await fetch(wasmPath);
const bytes = await response.arrayBuffer();
return bytes;
}
registerSingleton(ITextMateService, TextMateService);

View File

@@ -33,7 +33,7 @@ export class TMGrammarFactory extends Disposable {
private readonly _languageToScope2: string[];
private readonly _grammarRegistry: Registry;
constructor(host: ITMGrammarFactoryHost, grammarDefinitions: IValidGrammarDefinition[], vscodeTextmate: typeof import('vscode-textmate'), onigLib: Promise<IOnigLib> | undefined) {
constructor(host: ITMGrammarFactoryHost, grammarDefinitions: IValidGrammarDefinition[], vscodeTextmate: typeof import('vscode-textmate'), onigLib: Promise<IOnigLib>) {
super();
this._host = host;
this._initialState = vscodeTextmate.INITIAL;
@@ -41,8 +41,8 @@ export class TMGrammarFactory extends Disposable {
this._injections = {};
this._injectedEmbeddedLanguages = {};
this._languageToScope2 = [];
this._grammarRegistry = new vscodeTextmate.Registry({
getOnigLib: (typeof onigLib === 'undefined' ? undefined : () => onigLib),
this._grammarRegistry = this._register(new vscodeTextmate.Registry({
onigLib: onigLib,
loadGrammar: async (scopeName: string) => {
const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName);
if (!grammarDefinition) {
@@ -67,7 +67,7 @@ export class TMGrammarFactory extends Disposable {
}
return injections;
}
});
}));
for (const validGrammar of grammarDefinitions) {
this._scopeRegistry.register(validGrammar);

View File

@@ -5,41 +5,43 @@
"type": "other",
"other": {
"name": "lib-oniguruma",
"downloadUrl": "http://dl.fedoraproject.org/pub/epel/7/SRPMS/Packages/o/oniguruma-5.9.5-3.el7.src.rpm",
"version": "5.9.3"
"downloadUrl": "https://github.com/kkos/oniguruma",
"version": "6.9.5"
}
},
"licenseDetail": [
"Copyright (c) 2002-2007 K.Kosako. All rights reserved.",
"Oniguruma LICENSE",
"-----------------",
"",
"Copyright (c) 2002-2020 K.Kosako <kkosako0@gmail.com>",
"All rights reserved.",
"",
"The BSD License",
"",
"Redistribution and use in source and binary forms, with or without",
"modification, are permitted provided that the following conditions",
"are met:",
"",
"1. Redistributions of source code must retain the above copyright",
" notice, this list of conditions and the following disclaimer.",
"",
"2. Redistributions in binary form must reproduce the above copyright",
" notice, this list of conditions and the following disclaimer in the",
" documentation and/or other materials provided with the distribution.",
"",
"THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND",
"ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE",
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR",
"PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS",
"BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR",
"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF",
"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR",
"BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,",
"WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE",
"OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN",
"IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE",
"ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE",
"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL",
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS",
"OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)",
"HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT",
"LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY",
"OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF",
"SUCH DAMAGE."
],
"isOnlyProductionDependency": true,
"license": "BSD",
"version": "5.9.3"
"version": "6.9.5"
}
],
"version": 1

View File

@@ -15,6 +15,8 @@ export interface ITextMateService {
onDidEncounterLanguage: Event<LanguageId>;
createGrammar(modeId: string): Promise<IGrammar | null>;
startDebugMode(printFn: (str: string) => void, onStop: () => void): void;
}
// -------------- Types "liberated" from vscode-textmate due to usage in /common/

View File

@@ -13,7 +13,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { createWebWorker, MonacoWebWorker } from 'vs/editor/common/services/webWorker';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IOnigLib, IRawTheme } from 'vscode-textmate';
import { IRawTheme } from 'vscode-textmate';
import { IValidGrammarDefinition } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
import { TextMateWorker } from 'vs/workbench/services/textMate/electron-browser/textMateWorker';
import { ITextModel } from 'vs/editor/common/model';
@@ -24,6 +24,8 @@ import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGramma
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IProgressService } from 'vs/platform/progress/common/progress';
const RUN_TEXTMATE_IN_WORKER = false;
@@ -117,7 +119,7 @@ export class TextMateWorkerHost {
constructor(
private readonly textMateService: TextMateService,
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService
) {
}
@@ -146,9 +148,11 @@ export class TextMateService extends AbstractTextMateService {
@ILogService logService: ILogService,
@IConfigurationService configurationService: IConfigurationService,
@IStorageService storageService: IStorageService,
@IProgressService progressService: IProgressService,
@IModelService private readonly _modelService: IModelService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
) {
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService);
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService, progressService);
this._worker = null;
this._workerProxy = null;
this._tokenizers = Object.create(null);
@@ -177,12 +181,14 @@ export class TextMateService extends AbstractTextMateService {
}
}
protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> {
return import('vscode-textmate');
}
protected _loadOnigLib(): Promise<IOnigLib> | undefined {
return undefined;
protected async _loadVSCodeOnigurumWASM(): Promise<Response | ArrayBuffer> {
const wasmPath = (
this._environmentService.isBuilt
? require.toUrl('../../../../../../node_modules.asar.unpacked/vscode-oniguruma/release/onig.wasm')
: require.toUrl('../../../../../../node_modules/vscode-oniguruma/release/onig.wasm')
);
const response = await fetch(wasmPath);
return response;
}
protected _onDidCreateGrammarFactory(grammarDefinitions: IValidGrammarDefinition[]): void {

View File

@@ -11,7 +11,7 @@ import { TMGrammarFactory, ICreateGrammarResult } from 'vs/workbench/services/te
import { IModelChangedEvent, MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel';
import { TextMateWorkerHost } from 'vs/workbench/services/textMate/electron-browser/textMateService';
import { TokenizationStateStore } from 'vs/editor/common/model/textModelTokens';
import { IGrammar, StackElement, IRawTheme } from 'vscode-textmate';
import { IGrammar, StackElement, IRawTheme, IOnigLib } from 'vscode-textmate';
import { MultilineTokensBuilder, countEOL } from 'vs/editor/common/model/tokensStore';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
@@ -118,7 +118,7 @@ export class TextMateWorker {
private readonly _host: TextMateWorkerHost;
private readonly _models: { [uri: string]: TextMateWorkerModel; };
private readonly _grammarCache: Promise<ICreateGrammarResult>[];
private readonly _grammarFactory: TMGrammarFactory | null;
private readonly _grammarFactory: Promise<TMGrammarFactory | null>;
constructor(ctx: IWorkerContext<TextMateWorkerHost>, createData: ICreateData) {
this._host = ctx.host;
@@ -134,24 +134,36 @@ export class TextMateWorker {
injectTo: def.injectTo,
};
});
this._grammarFactory = this._loadTMGrammarFactory(grammarDefinitions);
}
const globalDefine = (<any>self).define;
try {
(<any>self).define.amd = undefined;
const vscodeTextmate = <typeof import('vscode-textmate')>require.__$__nodeRequire('vscode-textmate');
private async _loadTMGrammarFactory(grammarDefinitions: IValidGrammarDefinition[]): Promise<TMGrammarFactory> {
require.config({
paths: {
'vscode-textmate': '../node_modules/vscode-textmate/release/main',
'vscode-oniguruma': '../node_modules/vscode-oniguruma/release/main',
}
});
const vscodeTextmate = await import('vscode-textmate');
const vscodeOniguruma = await import('vscode-oniguruma');
const wasmPath = require.toUrl('vscode-oniguruma/../onig.wasm');
const response = await fetch(wasmPath);
// Using the response directly only works if the server sets the MIME type 'application/wasm'.
// Otherwise, a TypeError is thrown when using the streaming compiler.
// We therefore use the non-streaming compiler :(.
const bytes = await response.arrayBuffer();
await vscodeOniguruma.loadWASM(bytes);
this._grammarFactory = new TMGrammarFactory({
logTrace: (msg: string) => {/* console.log(msg) */ },
logError: (msg: string, err: any) => console.error(msg, err),
readFile: (resource: URI) => this._host.readFile(resource)
}, grammarDefinitions, vscodeTextmate, undefined);
} catch (err) {
console.error(err);
this._grammarFactory = null;
return;
} finally {
(<any>self).define = globalDefine;
}
const onigLib: Promise<IOnigLib> = Promise.resolve({
createOnigScanner: (sources) => vscodeOniguruma.createOnigScanner(sources),
createOnigString: (str) => vscodeOniguruma.createOnigString(str)
});
return new TMGrammarFactory({
logTrace: (msg: string) => {/* console.log(msg) */ },
logError: (msg: string, err: any) => console.error(msg, err),
readFile: (resource: URI) => this._host.readFile(resource)
}, grammarDefinitions, vscodeTextmate, onigLib);
}
public acceptNewModel(data: IRawModelData): void {
@@ -175,19 +187,21 @@ export class TextMateWorker {
}
}
public getOrCreateGrammar(languageId: LanguageId): Promise<ICreateGrammarResult | null> {
if (!this._grammarFactory) {
public async getOrCreateGrammar(languageId: LanguageId): Promise<ICreateGrammarResult | null> {
const grammarFactory = await this._grammarFactory;
if (!grammarFactory) {
return Promise.resolve(null);
}
if (!this._grammarCache[languageId]) {
this._grammarCache[languageId] = this._grammarFactory.createGrammar(languageId);
this._grammarCache[languageId] = grammarFactory.createGrammar(languageId);
}
return this._grammarCache[languageId];
}
public acceptTheme(theme: IRawTheme, colorMap: string[]): void {
if (this._grammarFactory) {
this._grammarFactory.setTheme(theme, colorMap);
public async acceptTheme(theme: IRawTheme, colorMap: string[]): Promise<void> {
const grammarFactory = await this._grammarFactory;
if (grammarFactory) {
grammarFactory.setTheme(theme, colorMap);
}
}

View File

@@ -220,8 +220,8 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
this.currentColorTheme.setCustomTokenColors(this.settings.tokenColorCustomizations);
hasColorChanges = true;
}
if (e.affectsConfiguration(ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL)) {
this.currentColorTheme.setCustomTokenStyleRules(this.settings.tokenStylesCustomizations);
if (e.affectsConfiguration(ThemeSettings.SEMANTIC_TOKEN_COLOR_CUSTOMIZATIONS) || e.affectsConfiguration(ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL)) {
this.currentColorTheme.setCustomSemanticTokenColors(this.settings.semanticTokenColorCustomizations, this.settings.experimentalSemanticTokenColorCustomizations);
hasColorChanges = true;
}
if (hasColorChanges) {

View File

@@ -6,7 +6,7 @@
import { basename } from 'vs/base/common/path';
import * as Json from 'vs/base/common/json';
import { Color } from 'vs/base/common/color';
import { ExtensionData, ITokenColorCustomizations, ITextMateThemingRule, IWorkbenchColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations, IExperimentalTokenStyleCustomizations, ITokenColorizationSetting } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ExtensionData, ITokenColorCustomizations, ITextMateThemingRule, IWorkbenchColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations, ISemanticTokenRules, ISemanticTokenColorizationSetting, ISemanticTokenColorCustomizations, IExperimentalSemanticTokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { convertSettings } from 'vs/workbench/services/themes/common/themeCompatibility';
import * as nls from 'vs/nls';
import * as types from 'vs/base/common/types';
@@ -20,7 +20,7 @@ import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
import { URI } from 'vs/base/common/uri';
import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser';
import { startsWith } from 'vs/base/common/strings';
import { TokenStyle, ProbeScope, TokenStylingRule, getTokenClassificationRegistry, TokenStyleValue, TokenStyleData, parseClassifierString } from 'vs/platform/theme/common/tokenClassificationRegistry';
import { TokenStyle, SemanticTokenRule, ProbeScope, getTokenClassificationRegistry, TokenStyleValue, TokenStyleData, parseClassifierString } from 'vs/platform/theme/common/tokenClassificationRegistry';
import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { CharCode } from 'vs/base/common/charCode';
@@ -42,7 +42,7 @@ const tokenGroupToScopesMap = {
};
export type TokenStyleDefinition = TokenStylingRule | ProbeScope[] | TokenStyleValue;
export type TokenStyleDefinition = SemanticTokenRule | ProbeScope[] | TokenStyleValue;
export type TokenStyleDefinitions = { [P in keyof TokenStyleData]?: TokenStyleDefinition | undefined };
export type TextMateThemingRuleDefinitions = { [P in keyof TokenStyleData]?: ITextMateThemingRule | undefined; } & { scope?: ProbeScope; };
@@ -62,14 +62,15 @@ export class ColorThemeData implements IWorkbenchColorTheme {
private themeSemanticHighlighting: boolean | undefined;
private customSemanticHighlighting: boolean | undefined;
private customSemanticHighlightingDeprecated: boolean | undefined;
private themeTokenColors: ITextMateThemingRule[] = [];
private customTokenColors: ITextMateThemingRule[] = [];
private colorMap: IColorMap = {};
private customColorMap: IColorMap = {};
private tokenStylingRules: TokenStylingRule[] = [];
private customTokenStylingRules: TokenStylingRule[] = [];
private semanticTokenRules: SemanticTokenRule[] = [];
private customSemanticTokenRules: SemanticTokenRule[] = [];
private themeTokenScopeMatchers: Matcher<ProbeScope>[] | undefined;
private customTokenScopeMatchers: Matcher<ProbeScope>[] | undefined;
@@ -85,7 +86,13 @@ export class ColorThemeData implements IWorkbenchColorTheme {
}
get semanticHighlighting(): boolean {
return this.customSemanticHighlighting !== undefined ? this.customSemanticHighlighting : !!this.themeSemanticHighlighting;
if (this.customSemanticHighlighting !== undefined) {
return this.customSemanticHighlighting;
}
if (this.customSemanticHighlightingDeprecated !== undefined) {
return this.customSemanticHighlightingDeprecated;
}
return !!this.themeSemanticHighlighting;
}
get tokenColors(): ITextMateThemingRule[] {
@@ -170,18 +177,16 @@ export class ColorThemeData implements IWorkbenchColorTheme {
}
}
}
for (const rule of this.tokenStylingRules) {
const matchScore = rule.selector.match(type, modifiers, language);
if (matchScore >= 0) {
_processStyle(matchScore, rule.style, rule);
}
}
for (const rule of this.customTokenStylingRules) {
function _processSemanticTokenRule(rule: SemanticTokenRule) {
const matchScore = rule.selector.match(type, modifiers, language);
if (matchScore >= 0) {
_processStyle(matchScore, rule.style, rule);
}
}
this.semanticTokenRules.forEach(_processSemanticTokenRule);
this.customSemanticTokenRules.forEach(_processSemanticTokenRule);
let hasUndefinedStyleProperty = false;
for (let k in score) {
const key = k as keyof TokenStyle;
@@ -240,14 +245,14 @@ export class ColorThemeData implements IWorkbenchColorTheme {
index.add(rule.settings.background);
});
this.tokenStylingRules.forEach(r => index.add(r.style.foreground));
this.semanticTokenRules.forEach(r => index.add(r.style.foreground));
tokenClassificationRegistry.getTokenStylingDefaultRules().forEach(r => {
const defaultColor = r.defaults[this.type];
if (defaultColor && typeof defaultColor === 'object') {
index.add(defaultColor.foreground);
}
});
this.customTokenStylingRules.forEach(r => index.add(r.style.foreground));
this.customSemanticTokenRules.forEach(r => index.add(r.style.foreground));
this.tokenColorIndex = index;
}
@@ -273,11 +278,11 @@ export class ColorThemeData implements IWorkbenchColorTheme {
};
}
public getTokenStylingRuleScope(rule: TokenStylingRule): 'setting' | 'theme' | undefined {
if (this.customTokenStylingRules.indexOf(rule) !== -1) {
public getTokenStylingRuleScope(rule: SemanticTokenRule): 'setting' | 'theme' | undefined {
if (this.customSemanticTokenRules.indexOf(rule) !== -1) {
return 'setting';
}
if (this.tokenStylingRules.indexOf(rule) !== -1) {
if (this.semanticTokenRules.indexOf(rule) !== -1) {
return 'theme';
}
return undefined;
@@ -346,7 +351,7 @@ export class ColorThemeData implements IWorkbenchColorTheme {
public setCustomizations(settings: ThemeConfiguration) {
this.setCustomColors(settings.colorCustomizations);
this.setCustomTokenColors(settings.tokenColorCustomizations);
this.setCustomTokenStyleRules(settings.tokenStylesCustomizations);
this.setCustomSemanticTokenColors(settings.semanticTokenColorCustomizations, settings.experimentalSemanticTokenColorCustomizations);
}
public setCustomColors(colors: IColorCustomizations) {
@@ -374,7 +379,7 @@ export class ColorThemeData implements IWorkbenchColorTheme {
public setCustomTokenColors(customTokenColors: ITokenColorCustomizations) {
this.customTokenColors = [];
this.customSemanticHighlighting = undefined;
this.customSemanticHighlightingDeprecated = undefined;
// first add the non-theme specific settings
this.addCustomTokenColors(customTokenColors);
@@ -390,19 +395,53 @@ export class ColorThemeData implements IWorkbenchColorTheme {
this.customTokenScopeMatchers = undefined;
}
public setCustomTokenStyleRules(tokenStylingRules: IExperimentalTokenStyleCustomizations) {
this.customTokenStylingRules = [];
readCustomTokenStyleRules(tokenStylingRules, this.customTokenStylingRules);
public setCustomSemanticTokenColors(semanticTokenColors: ISemanticTokenColorCustomizations | undefined, experimental?: IExperimentalSemanticTokenColorCustomizations) {
this.customSemanticTokenRules = [];
this.customSemanticHighlighting = undefined;
const themeSpecificColors = tokenStylingRules[`[${this.settingsId}]`] as IExperimentalTokenStyleCustomizations;
if (types.isObject(themeSpecificColors)) {
readCustomTokenStyleRules(themeSpecificColors, this.customTokenStylingRules);
if (experimental) { // apply deprecated settings first
this.readSemanticTokenRules(experimental);
const themeSpecificColors = experimental[`[${this.settingsId}]`] as IExperimentalSemanticTokenColorCustomizations;
if (types.isObject(themeSpecificColors)) {
this.readSemanticTokenRules(themeSpecificColors);
}
}
if (semanticTokenColors) {
this.customSemanticHighlighting = semanticTokenColors.enabled;
if (semanticTokenColors.rules) {
this.readSemanticTokenRules(semanticTokenColors.rules);
}
const themeSpecificColors = semanticTokenColors[`[${this.settingsId}]`] as ISemanticTokenColorCustomizations;
if (types.isObject(themeSpecificColors)) {
if (themeSpecificColors.enabled !== undefined) {
this.customSemanticHighlighting = themeSpecificColors.enabled;
}
if (themeSpecificColors.rules) {
this.readSemanticTokenRules(themeSpecificColors.rules);
}
}
}
this.tokenColorIndex = undefined;
this.textMateThemingRules = undefined;
}
private readSemanticTokenRules(tokenStylingRuleSection: ISemanticTokenRules) {
for (let key in tokenStylingRuleSection) {
if (key[0] !== '[') { // still do this test until experimental settings are gone
try {
const rule = readSemanticTokenRule(key, tokenStylingRuleSection[key]);
if (rule) {
this.customSemanticTokenRules.push(rule);
}
} catch (e) {
// invalid selector, ignore
}
}
}
}
private addCustomTokenColors(customTokenColors: ITokenColorCustomizations) {
// Put the general customizations such as comments, strings, etc. first so that
// they can be overridden by specific customizations like "string.interpolated"
@@ -427,7 +466,7 @@ export class ColorThemeData implements IWorkbenchColorTheme {
}
}
if (customTokenColors.semanticHighlighting !== undefined) {
this.customSemanticHighlighting = customTokenColors.semanticHighlighting;
this.customSemanticHighlightingDeprecated = customTokenColors.semanticHighlighting;
}
}
@@ -449,12 +488,12 @@ export class ColorThemeData implements IWorkbenchColorTheme {
const result = {
colors: {},
textMateRules: [],
stylingRules: [],
semanticTokenRules: [],
semanticHighlighting: false
};
return _loadColorTheme(extensionResourceLoaderService, this.location, result).then(_ => {
this.isLoaded = true;
this.tokenStylingRules = result.stylingRules;
this.semanticTokenRules = result.semanticTokenRules;
this.colorMap = result.colors;
this.themeTokenColors = result.textMateRules;
this.themeSemanticHighlighting = result.semanticHighlighting;
@@ -480,7 +519,7 @@ export class ColorThemeData implements IWorkbenchColorTheme {
settingsId: this.settingsId,
selector: this.id.split(' ').join('.'), // to not break old clients
themeTokenColors: this.themeTokenColors,
tokenStylingRules: this.tokenStylingRules.map(TokenStylingRule.toJSONObject),
semanticTokenRules: this.semanticTokenRules.map(SemanticTokenRule.toJSONObject),
extensionData: ExtensionData.toJSONObject(this.extensionData),
location: this.location?.toJSON(),
themeSemanticHighlighting: this.themeSemanticHighlighting,
@@ -493,7 +532,7 @@ export class ColorThemeData implements IWorkbenchColorTheme {
hasEqualData(other: ColorThemeData) {
return objects.equals(this.colorMap, other.colorMap)
&& objects.equals(this.themeTokenColors, other.themeTokenColors)
&& arrays.equals(this.tokenStylingRules, other.tokenStylingRules, TokenStylingRule.equals)
&& arrays.equals(this.semanticTokenRules, other.semanticTokenRules, SemanticTokenRule.equals)
&& this.themeSemanticHighlighting === other.themeSemanticHighlighting;
}
@@ -547,13 +586,13 @@ export class ColorThemeData implements IWorkbenchColorTheme {
case 'id': case 'label': case 'settingsId': case 'watch': case 'themeSemanticHighlighting':
(theme as any)[key] = data[key];
break;
case 'tokenStylingRules':
case 'semanticTokenRules':
const rulesData = data[key];
if (Array.isArray(rulesData)) {
for (let d of rulesData) {
const rule = TokenStylingRule.fromJSONObject(tokenClassificationRegistry, d);
const rule = SemanticTokenRule.fromJSONObject(tokenClassificationRegistry, d);
if (rule) {
theme.tokenStylingRules.push(rule);
theme.semanticTokenRules.push(rule);
}
}
}
@@ -605,7 +644,7 @@ function toCSSSelector(extensionId: string, path: string) {
return str;
}
async function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap, stylingRules: TokenStylingRule[], semanticHighlighting: boolean }): Promise<any> {
async function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap, semanticTokenRules: SemanticTokenRule[], semanticHighlighting: boolean }): Promise<any> {
if (resources.extname(themeLocation) === '.json') {
const content = await extensionResourceLoaderService.readExtensionResource(themeLocation);
let errors: Json.ParseError[] = [];
@@ -650,9 +689,9 @@ async function _loadColorTheme(extensionResourceLoaderService: IExtensionResourc
if (semanticTokenColors && typeof semanticTokenColors === 'object') {
for (let key in semanticTokenColors) {
try {
const rule = readCustomTokenStyleRule(key, semanticTokenColors[key]);
const rule = readSemanticTokenRule(key, semanticTokenColors[key]);
if (rule) {
result.stylingRules.push(rule);
result.semanticTokenRules.push(rule);
}
} catch (e) {
return Promise.reject(new Error(nls.localize({ key: 'error.invalidformat.semanticTokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'semanticTokenColors' conatains a invalid selector", themeLocation.toString())));
@@ -770,13 +809,13 @@ function getScopeMatcher(rule: ITextMateThemingRule): Matcher<ProbeScope> {
};
}
function readCustomTokenStyleRule(selectorString: string, settings: ITokenColorizationSetting | string | undefined): TokenStylingRule | undefined {
function readSemanticTokenRule(selectorString: string, settings: ISemanticTokenColorizationSetting | string | boolean | undefined): SemanticTokenRule | undefined {
const selector = tokenClassificationRegistry.parseTokenSelector(selectorString);
let style: TokenStyle | undefined;
if (typeof settings === 'string') {
style = TokenStyle.fromSettings(settings, undefined);
} else if (isTokenColorizationSetting(settings)) {
style = TokenStyle.fromSettings(settings.foreground, settings.fontStyle);
} else if (isSemanticTokenColorizationSetting(settings)) {
style = TokenStyle.fromSettings(settings.foreground, settings.fontStyle, settings.bold, settings.underline, settings.italic);
}
if (style) {
return { selector, style };
@@ -784,24 +823,9 @@ function readCustomTokenStyleRule(selectorString: string, settings: ITokenColori
return undefined;
}
function readCustomTokenStyleRules(tokenStylingRuleSection: IExperimentalTokenStyleCustomizations, result: TokenStylingRule[] = []) {
for (let key in tokenStylingRuleSection) {
if (key[0] !== '[') {
try {
const rule = readCustomTokenStyleRule(key, tokenStylingRuleSection[key]);
if (rule) {
result.push(rule);
}
} catch (e) {
// invalid selector, ignore
}
}
}
return result;
}
function isTokenColorizationSetting(style: any): style is ITokenColorizationSetting {
return style && (style.foreground || style.fontStyle);
function isSemanticTokenColorizationSetting(style: any): style is ISemanticTokenColorizationSetting {
return style && (types.isString(style.foreground) || types.isString(style.fontStyle) || types.isBoolean(style.italic)
|| types.isBoolean(style.underline) || types.isBoolean(style.bold));
}

View File

@@ -12,7 +12,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { textmateColorsSchemaId, textmateColorGroupSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema';
import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry';
import { tokenStylingSchemaId } from 'vs/platform/theme/common/tokenClassificationRegistry';
import { ThemeSettings, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IColorCustomizations, ITokenColorCustomizations, IExperimentalTokenStyleCustomizations, IWorkbenchProductIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ThemeSettings, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IColorCustomizations, ITokenColorCustomizations, IWorkbenchProductIconTheme, ISemanticTokenColorCustomizations, IExperimentalSemanticTokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
const DEFAULT_THEME_SETTING_VALUE = 'Default Light Azure Data Studio'; // {{SQL CARBON EDIT}} replace default theme
@@ -134,19 +134,43 @@ const tokenColorSchema: IJSONSchema = {
},
semanticHighlighting: {
description: nls.localize('editorColors.semanticHighlighting', 'Whether semantic highlighting should be enabled for this theme.'),
deprecationMessage: nls.localize('editorColors.semanticHighlighting.deprecationMessage', 'Use `enabled` in `editor.semanticTokenColorCustomizations` setting instead.'),
type: 'boolean'
}
}
};
const tokenColorCustomizationSchema: IConfigurationPropertySchema = {
description: nls.localize('editorColors', "Overrides editor colors and font style from the currently selected color theme."),
description: nls.localize('editorColors', "Overrides editor syntax colors and font style from the currently selected color theme."),
default: {},
allOf: [tokenColorSchema]
};
const experimentalTokenStylingCustomizationSchema: IConfigurationPropertySchema = {
description: nls.localize('editorColorsTokenStyles', "Overrides token color and styles from the currently selected color theme."),
const semanticTokenColorSchema: IJSONSchema = {
type: 'object',
properties: {
enabled: {
type: 'boolean',
description: nls.localize('editorColors.semanticHighlighting.enabled', 'Whether semantic highlighting is enabled or disabled for this theme')
},
rules: {
$ref: tokenStylingSchemaId,
description: nls.localize('editorColors.semanticHighlighting.rules', 'Semantic token styling rules for this theme.')
}
},
additionalProperties: false
};
const semanticTokenColorCustomizationSchema: IConfigurationPropertySchema = {
description: nls.localize('semanticTokenColors', "Overrides editor semantic token color and styles from the currently selected color theme."),
default: {},
allOf: [{ $ref: tokenStylingSchemaId }]
allOf: [{ ...semanticTokenColorSchema, patternProperties: { '^\\[': {} } }]
};
const experimentalTokenStylingCustomizationSchema: IConfigurationPropertySchema = {
deprecationMessage: nls.localize('editorColors.experimentalTokenStyling.deprecationMessage', 'Use `editor.semanticTokenColorCustomizations` instead.'),
default: {},
allOf: [{ $ref: tokenStylingSchemaId }],
};
const tokenColorCustomizationConfiguration: IConfigurationNode = {
id: 'editor',
@@ -154,6 +178,7 @@ const tokenColorCustomizationConfiguration: IConfigurationNode = {
type: 'object',
properties: {
[ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS]: tokenColorCustomizationSchema,
[ThemeSettings.SEMANTIC_TOKEN_COLOR_CUSTOMIZATIONS]: semanticTokenColorCustomizationSchema,
[ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL]: experimentalTokenStylingCustomizationSchema
}
};
@@ -167,22 +192,24 @@ export function updateColorThemeConfigurationSchemas(themes: IWorkbenchColorThem
const themeSpecificWorkbenchColors: IJSONSchema = { properties: {} };
const themeSpecificTokenColors: IJSONSchema = { properties: {} };
const themeSpecificTokenStyling: IJSONSchema = { properties: {} };
const themeSpecificSemanticTokenColors: IJSONSchema = { properties: {} };
const experimentalThemeSpecificSemanticTokenColors: IJSONSchema = { properties: {} };
const workbenchColors = { $ref: workbenchColorsSchemaId, additionalProperties: false };
const tokenColors = { properties: tokenColorSchema.properties, additionalProperties: false };
const tokenStyling = { $ref: tokenStylingSchemaId, additionalProperties: false };
for (let t of themes) {
// add theme specific color customization ("[Abyss]":{ ... })
const themeId = `[${t.settingsId}]`;
themeSpecificWorkbenchColors.properties![themeId] = workbenchColors;
themeSpecificTokenColors.properties![themeId] = tokenColors;
themeSpecificTokenStyling.properties![themeId] = tokenStyling;
themeSpecificSemanticTokenColors.properties![themeId] = semanticTokenColorSchema;
experimentalThemeSpecificSemanticTokenColors.properties![themeId] = { $ref: tokenStylingSchemaId, additionalProperties: false };
}
colorCustomizationsSchema.allOf![1] = themeSpecificWorkbenchColors;
tokenColorCustomizationSchema.allOf![1] = themeSpecificTokenColors;
experimentalTokenStylingCustomizationSchema.allOf![1] = themeSpecificTokenStyling;
semanticTokenColorCustomizationSchema.allOf![1] = themeSpecificSemanticTokenColors;
experimentalTokenStylingCustomizationSchema.allOf![1] = experimentalThemeSpecificSemanticTokenColors;
configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration, tokenColorCustomizationConfiguration);
}
@@ -226,8 +253,12 @@ export class ThemeConfiguration {
return this.configurationService.getValue<ITokenColorCustomizations>(ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS) || {};
}
public get tokenStylesCustomizations(): IExperimentalTokenStyleCustomizations {
return this.configurationService.getValue<IExperimentalTokenStyleCustomizations>(ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL) || {};
public get semanticTokenColorCustomizations(): ISemanticTokenColorCustomizations | undefined {
return this.configurationService.getValue<ISemanticTokenColorCustomizations>(ThemeSettings.SEMANTIC_TOKEN_COLOR_CUSTOMIZATIONS);
}
public get experimentalSemanticTokenColorCustomizations(): IExperimentalSemanticTokenColorCustomizations | undefined {
return this.configurationService.getValue<IExperimentalSemanticTokenColorCustomizations>(ThemeSettings.TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL);
}
public async setColorTheme(theme: IWorkbenchColorTheme, settingsTarget: ConfigurationTarget | undefined | 'auto'): Promise<IWorkbenchColorTheme> {

View File

@@ -25,6 +25,7 @@ export enum ThemeSettings {
PRODUCT_ICON_THEME = 'workbench.productIconTheme',
COLOR_CUSTOMIZATIONS = 'workbench.colorCustomizations',
TOKEN_COLOR_CUSTOMIZATIONS = 'editor.tokenColorCustomizations',
SEMANTIC_TOKEN_COLOR_CUSTOMIZATIONS = 'editor.semanticTokenColorCustomizations',
TOKEN_COLOR_CUSTOMIZATIONS_EXPERIMENTAL = 'editor.tokenColorCustomizationsExperimental',
PREFERRED_DARK_THEME = 'workbench.preferredDarkColorTheme',
@@ -93,11 +94,21 @@ export interface ITokenColorCustomizations {
functions?: string | ITokenColorizationSetting;
variables?: string | ITokenColorizationSetting;
textMateRules?: ITextMateThemingRule[];
semanticHighlighting?: boolean;
semanticHighlighting?: boolean; // deprecated, use ISemanticTokenColorCustomizations.enabled instead
}
export interface IExperimentalTokenStyleCustomizations {
[styleRuleOrThemeSettingsId: string]: string | ITokenColorizationSetting | IExperimentalTokenStyleCustomizations | undefined;
export interface ISemanticTokenColorCustomizations {
enabled?: boolean;
rules?: ISemanticTokenRules;
[styleRuleOrThemeSettingsId: string]: ISemanticTokenRules | ISemanticTokenColorCustomizations | boolean | undefined;
}
export interface IExperimentalSemanticTokenColorCustomizations {
[styleRuleOrThemeSettingsId: string]: ISemanticTokenRules | IExperimentalSemanticTokenColorCustomizations | undefined;
}
export interface ISemanticTokenRules {
[selector: string]: string | ISemanticTokenColorizationSetting | undefined;
}
export interface ITextMateThemingRule {
@@ -112,6 +123,14 @@ export interface ITokenColorizationSetting {
fontStyle?: string; /* [italic|underline|bold] */
}
export interface ISemanticTokenColorizationSetting {
foreground?: string;
fontStyle?: string; /* [italic|underline|bold] */
bold?: boolean;
underline?: boolean;
italic?: boolean;
}
export interface ExtensionData {
extensionId: string;
extensionPublisher: string;

View File

@@ -99,7 +99,7 @@ suite('Themes - TokenStyleResolving', () => {
assertTokenStyles(themeData, {
'comment': ts('#88846f', undefinedStyle),
'variable': ts('#F8F8F2', unsetStyle),
'type': ts('#A6E22E', { underline: true }),
'type': ts('#A6E22E', { bold: false, underline: true, italic: false }),
'function': ts('#A6E22E', unsetStyle),
'string': ts('#E6DB74', undefinedStyle),
'number': ts('#AE81FF', undefinedStyle),
@@ -199,7 +199,7 @@ suite('Themes - TokenStyleResolving', () => {
assertTokenStyles(themeData, {
'comment': ts('#384887', undefinedStyle),
'variable': ts(undefined, unsetStyle),
'type': ts('#ffeebb', { underline: true }),
'type': ts('#ffeebb', { underline: true, bold: false, italic: false }),
'function': ts('#ddbb88', unsetStyle),
'string': ts('#22aa44', undefinedStyle),
'number': ts('#f280d0', undefinedStyle),
@@ -271,19 +271,19 @@ suite('Themes - TokenStyleResolving', () => {
assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators');
tokenStyle = themeData.resolveScopes([['storage']]);
assertTokenStyle(tokenStyle, ts('#F92672', { italic: true }), 'storage');
assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, bold: false, underline: false }), 'storage');
tokenStyle = themeData.resolveScopes([['storage.type']]);
assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type');
assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, bold: false, underline: false }), 'storage.type');
tokenStyle = themeData.resolveScopes([['entity.name.class']]);
assertTokenStyle(tokenStyle, ts('#A6E22E', { underline: true }), 'entity.name.class');
assertTokenStyle(tokenStyle, ts('#A6E22E', { italic: false, bold: false, underline: true }), 'entity.name.class');
tokenStyle = themeData.resolveScopes([['meta.structure.dictionary.json', 'string.quoted.double.json']]);
assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property');
tokenStyle = themeData.resolveScopes([['keyword'], ['storage.type'], ['entity.name.class']]);
assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type');
assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true, bold: false, underline: false }), 'storage.type');
});
@@ -318,7 +318,7 @@ suite('Themes - TokenStyleResolving', () => {
themeData.setCustomTokenColors(customTokenColors);
const tokenStyle = themeData.resolveScopes([['entity.name.type.class']]);
assertTokenStyle(tokenStyle, ts('#FF00FF', { underline: true }), 'entity.name.type.class');
assertTokenStyle(tokenStyle, ts('#FF00FF', { italic: false, bold: false, underline: true }), 'entity.name.type.class');
});
@@ -326,13 +326,16 @@ suite('Themes - TokenStyleResolving', () => {
test('rule matching', async () => {
const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test');
themeData.setCustomColors({ 'editor.foreground': '#000000' });
themeData.setCustomTokenStyleRules({
'type': '#ff0000',
'class': { foreground: '#0000ff', fontStyle: 'italic' },
'*.static': { fontStyle: 'bold' },
'*.declaration': { fontStyle: 'italic' },
'*.async.static': { fontStyle: 'italic underline' },
'*.async': { foreground: '#000fff', fontStyle: 'underline' }
themeData.setCustomSemanticTokenColors({
enabled: true,
rules: {
'type': '#ff0000',
'class': { foreground: '#0000ff', italic: true },
'*.static': { bold: true },
'*.declaration': { italic: true },
'*.async.static': { italic: true, underline: true },
'*.async': { foreground: '#000fff', underline: true }
}
});
assertTokenStyles(themeData, {
@@ -340,7 +343,7 @@ suite('Themes - TokenStyleResolving', () => {
'type.static': ts('#ff0000', { bold: true }),
'type.static.declaration': ts('#ff0000', { bold: true, italic: true }),
'class': ts('#0000ff', { italic: true }),
'class.static.declaration': ts('#0000ff', { bold: true, italic: true }),
'class.static.declaration': ts('#0000ff', { bold: true, italic: true, }),
'class.declaration': ts('#0000ff', { italic: true }),
'class.declaration.async': ts('#000fff', { underline: true, italic: true }),
'class.declaration.async.static': ts('#000fff', { italic: true, underline: true, bold: true }),
@@ -357,18 +360,24 @@ suite('Themes - TokenStyleResolving', () => {
try {
const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test');
themeData.setCustomColors({ 'editor.foreground': '#000000' });
themeData.setCustomTokenStyleRules({
'interface': '#ff0000',
'myTestInterface': { fontStyle: 'italic' },
'interface.static': { fontStyle: 'bold' }
themeData.setCustomSemanticTokenColors({
enabled: true,
rules: {
'interface': '#ff0000',
'myTestInterface': { italic: true },
'interface.static': { bold: true }
}
});
assertTokenStyles(themeData, { 'myTestSubInterface': ts('#ff0000', { italic: true }) });
assertTokenStyles(themeData, { 'myTestSubInterface.static': ts('#ff0000', { italic: true, bold: true }) });
themeData.setCustomTokenStyleRules({
'interface': '#ff0000',
'myTestInterface': { foreground: '#ff00ff', fontStyle: 'italic' }
themeData.setCustomSemanticTokenColors({
enabled: true,
rules: {
'interface': '#ff0000',
'myTestInterface': { foreground: '#ff00ff', italic: true }
}
});
assertTokenStyles(themeData, { 'myTestSubInterface': ts('#ff00ff', { italic: true }) });
} finally {
@@ -381,11 +390,14 @@ suite('Themes - TokenStyleResolving', () => {
try {
const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test');
themeData.setCustomColors({ 'editor.foreground': '#000000' });
themeData.setCustomTokenStyleRules({
'interface': '#fff000',
'interface:java': '#ff0000',
'interface.static': { fontStyle: 'bold' },
'interface.static:typescript': { fontStyle: 'italic' }
themeData.setCustomSemanticTokenColors({
enabled: true,
rules: {
'interface': '#fff000',
'interface:java': '#ff0000',
'interface.static': { bold: true },
'interface.static:typescript': { italic: true }
}
});
assertTokenStyles(themeData, { 'interface': ts('#ff0000', undefined) }, 'java');

View File

@@ -29,6 +29,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
_serviceBrand: undefined;
private static readonly CACHED_VIEW_POSITIONS = 'views.cachedViewPositions';
private static readonly CACHED_VIEW_CONTAINER_LOCATIONS = 'views.cachedViewContainerLocations';
private static readonly COMMON_CONTAINER_ID_PREFIX = 'workbench.views.service';
private readonly _onDidChangeContainer: Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._register(new Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>());
@@ -37,6 +38,9 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
private readonly _onDidChangeLocation: Emitter<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }> = this._register(new Emitter<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }>());
readonly onDidChangeLocation: Event<{ views: IViewDescriptor[], from: ViewContainerLocation, to: ViewContainerLocation }> = this._onDidChangeLocation.event;
private readonly _onDidChangeContainerLocation: Emitter<{ viewContainer: ViewContainer, from: ViewContainerLocation, to: ViewContainerLocation }> = this._register(new Emitter<{ viewContainer: ViewContainer, from: ViewContainerLocation, to: ViewContainerLocation }>());
readonly onDidChangeContainerLocation: Event<{ viewContainer: ViewContainer, from: ViewContainerLocation, to: ViewContainerLocation }> = this._onDidChangeContainerLocation.event;
private readonly viewContainerModels: Map<ViewContainer, { viewContainerModel: ViewContainerModel, disposable: IDisposable; }>;
private readonly activeViewContextKeys: Map<string, IContextKey<boolean>>;
private readonly movableViewContextKeys: Map<string, IContextKey<boolean>>;
@@ -46,6 +50,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
private readonly viewContainersRegistry: IViewContainersRegistry;
private cachedViewInfo: Map<string, ICachedViewContainerInfo>;
private cachedViewContainerInfo: Map<string, ViewContainerLocation>;
private _cachedViewPositionsValue: string | undefined;
private get cachedViewPositionsValue(): string {
@@ -63,6 +68,22 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
}
}
private _cachedViewContainerLocationsValue: string | undefined;
private get cachedViewContainerLocationsValue(): string {
if (!this._cachedViewContainerLocationsValue) {
this._cachedViewContainerLocationsValue = this.getStoredCachedViewContainerLocationsValue();
}
return this._cachedViewContainerLocationsValue;
}
private set cachedViewContainerLocationsValue(value: string) {
if (this._cachedViewContainerLocationsValue !== value) {
this._cachedViewContainerLocationsValue = value;
this.setStoredCachedViewContainerLocationsValue(value);
}
}
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@@ -83,9 +104,10 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
this.viewsRegistry = Registry.as<IViewsRegistry>(ViewExtensions.ViewsRegistry);
this.cachedViewInfo = this.getCachedViewPositions();
this.cachedViewContainerInfo = this.getCachedViewContainerLocations();
// Register all containers that were registered before this ctor
this.viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
this.getViewContainers().forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
// Try generating all generated containers that don't need extensions
this.tryGenerateContainers();
@@ -252,6 +274,11 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
}
getViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation {
const location = this.cachedViewContainerInfo.get(viewContainer.id);
return location !== undefined ? location : this.getDefaultViewContainerLocation(viewContainer);
}
getDefaultViewContainerLocation(viewContainer: ViewContainer): ViewContainerLocation {
return this.viewContainersRegistry.getViewContainerLocation(viewContainer);
}
@@ -267,14 +294,29 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
return this.viewContainersRegistry.get(id) || null;
}
getViewContainersByLocation(location: ViewContainerLocation): ViewContainer[] {
return this.viewContainersRegistry.getViewContainers(location);
return this.getViewContainers().filter(v => this.getViewContainerLocation(v) === location);
}
getViewContainers(): ViewContainer[] {
return this.viewContainersRegistry.all;
}
moveViewContainerToLocation(viewContainer: ViewContainer, location: ViewContainerLocation): void {
// to be implemented
const from = this.getViewContainerLocation(viewContainer);
const to = location;
if (from !== to) {
if (this.getDefaultViewContainerLocation(viewContainer) === to) {
this.cachedViewContainerInfo.delete(viewContainer.id);
} else {
this.cachedViewContainerInfo.set(viewContainer.id, to);
}
this._onDidChangeContainerLocation.fire({ viewContainer, from, to });
const views = this.getViewsByContainer(viewContainer);
this._onDidChangeLocation.fire({ views, from, to });
this.saveViewContainerLocationsToCache();
}
}
moveViewToLocation(view: IViewDescriptor, location: ViewContainerLocation): void {
@@ -376,6 +418,10 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
return result;
}
private getCachedViewContainerLocations(): Map<string, ViewContainerLocation> {
return new Map<string, ViewContainerLocation>(JSON.parse(this.cachedViewContainerLocationsValue));
}
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
if (e.key === ViewDescriptorService.CACHED_VIEW_POSITIONS && e.scope === StorageScope.GLOBAL
&& this.cachedViewPositionsValue !== this.getStoredCachedViewPositionsValue() /* This checks if current window changed the value or not */) {
@@ -407,7 +453,7 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
}
// If a value is not present in the cache, it must be reset to default
this.viewContainersRegistry.all.forEach(viewContainer => {
this.getViewContainers().forEach(viewContainer => {
const viewContainerModel = this.getViewContainerModel(viewContainer);
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
if (!newCachedPositions.has(viewDescriptor.id)) {
@@ -424,6 +470,35 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
this.cachedViewInfo = this.getCachedViewPositions();
}
if (e.key === ViewDescriptorService.CACHED_VIEW_CONTAINER_LOCATIONS && e.scope === StorageScope.GLOBAL
&& this.cachedViewContainerLocationsValue !== this.getStoredCachedViewContainerLocationsValue() /* This checks if current window changed the value or not */) {
this._cachedViewContainerLocationsValue = this.getStoredCachedViewContainerLocationsValue();
const newCachedLocations = this.getCachedViewContainerLocations();
for (const [containerId, location] of newCachedLocations.entries()) {
const container = this.getViewContainerById(containerId);
if (container) {
if (location !== this.getViewContainerLocation(container)) {
this.moveViewContainerToLocation(container, location);
}
}
}
this.getViewContainers().forEach(viewContainer => {
if (!newCachedLocations.has(viewContainer.id)) {
const currentLocation = this.getViewContainerLocation(viewContainer);
const defaultLocation = this.getDefaultViewContainerLocation(viewContainer);
if (currentLocation !== defaultLocation) {
this.moveViewContainerToLocation(viewContainer, defaultLocation);
}
}
});
this.cachedViewContainerInfo = this.getCachedViewContainerLocations();
}
}
// Generated Container Id Format
@@ -442,8 +517,16 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
this.storageService.store(ViewDescriptorService.CACHED_VIEW_POSITIONS, value, StorageScope.GLOBAL);
}
private getStoredCachedViewContainerLocationsValue(): string {
return this.storageService.get(ViewDescriptorService.CACHED_VIEW_CONTAINER_LOCATIONS, StorageScope.GLOBAL, '[]');
}
private setStoredCachedViewContainerLocationsValue(value: string): void {
this.storageService.store(ViewDescriptorService.CACHED_VIEW_CONTAINER_LOCATIONS, value, StorageScope.GLOBAL);
}
private saveViewPositionsToCache(): void {
this.viewContainersRegistry.all.forEach(viewContainer => {
this.getViewContainers().forEach(viewContainer => {
const viewContainerModel = this.getViewContainerModel(viewContainer);
viewContainerModel.allViewDescriptors.forEach(viewDescriptor => {
const containerLocation = this.getViewContainerLocation(viewContainer);
@@ -467,6 +550,17 @@ export class ViewDescriptorService extends Disposable implements IViewDescriptor
this.cachedViewPositionsValue = JSON.stringify([...this.cachedViewInfo]);
}
private saveViewContainerLocationsToCache(): void {
for (const [containerId, location] of this.cachedViewContainerInfo) {
const container = this.getViewContainerById(containerId);
if (container && location === this.getDefaultViewContainerLocation(container)) {
this.cachedViewContainerInfo.delete(containerId);
}
}
this.cachedViewContainerLocationsValue = JSON.stringify([...this.cachedViewContainerInfo]);
}
private getViewsByContainer(viewContainer: ViewContainer): IViewDescriptor[] {
const result = this.viewsRegistry.getViews(viewContainer).filter(viewDescriptor => {
const cachedContainer = this.cachedViewInfo.get(viewDescriptor.id)?.containerId || viewContainer.id;

View File

@@ -381,11 +381,11 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode
const viewDescriptor = viewDescriptorItem.viewDescriptor;
if (!viewDescriptor.canToggleVisibility) {
throw new Error(`Can't toggle this view's visibility`);
continue;
}
if (this.isViewDescriptorVisible(viewDescriptorItem) === visible) {
return;
if (this.isViewDescriptorVisibleWhenActive(viewDescriptorItem) === visible) {
continue;
}
if (viewDescriptor.workspace) {
@@ -398,6 +398,11 @@ export class ViewContainerModel extends Disposable implements IViewContainerMode
viewDescriptorItem.state.size = size;
}
if (this.isViewDescriptorVisible(viewDescriptorItem) !== visible) {
// do not add events if visibility is not changed
continue;
}
if (visible) {
added.push({ index: visibleIndex, viewDescriptor, size: viewDescriptorItem.state.size, collapsed: !!viewDescriptorItem.state.collapsed });
} else {

View File

@@ -382,4 +382,86 @@ suite('ViewContainerModel', () => {
assert.ok(!targetEvent.called, 'remove event should not be called since it is already hidden');
});
test('add event is not triggered if view was set visible (when visible) and not active', async function () {
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
const testObject = viewDescriptorService.getViewContainerModel(container);
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
const viewDescriptor: IViewDescriptor = {
id: 'view1',
ctorDescriptor: null!,
name: 'Test View 1',
when: ContextKeyExpr.equals('showview1', true),
canToggleVisibility: true
};
const key = contextKeyService.createKey('showview1', true);
key.set(false);
ViewsRegistry.registerViews([viewDescriptor], container);
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
const targetEvent = sinon.spy(testObject.onDidAddVisibleViewDescriptors);
testObject.setVisible('view1', true);
assert.ok(!targetEvent.called, 'add event should not be called since it is already visible');
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
});
test('remove event is not triggered if view was hidden and not active', async function () {
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
const testObject = viewDescriptorService.getViewContainerModel(container);
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
const viewDescriptor: IViewDescriptor = {
id: 'view1',
ctorDescriptor: null!,
name: 'Test View 1',
when: ContextKeyExpr.equals('showview1', true),
canToggleVisibility: true
};
const key = contextKeyService.createKey('showview1', true);
key.set(false);
ViewsRegistry.registerViews([viewDescriptor], container);
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
const targetEvent = sinon.spy(testObject.onDidAddVisibleViewDescriptors);
testObject.setVisible('view1', false);
assert.ok(!targetEvent.called, 'add event should not be called since it is disabled');
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
});
test('add event is not triggered if view was set visible (when not visible) and not active', async function () {
container = ViewContainerRegistry.registerViewContainer({ id: 'test', name: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
const testObject = viewDescriptorService.getViewContainerModel(container);
const target = disposableStore.add(new ViewDescriptorSequence(testObject));
const viewDescriptor: IViewDescriptor = {
id: 'view1',
ctorDescriptor: null!,
name: 'Test View 1',
when: ContextKeyExpr.equals('showview1', true),
canToggleVisibility: true
};
const key = contextKeyService.createKey('showview1', true);
key.set(false);
ViewsRegistry.registerViews([viewDescriptor], container);
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
testObject.setVisible('view1', false);
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
const targetEvent = sinon.spy(testObject.onDidAddVisibleViewDescriptors);
testObject.setVisible('view1', true);
assert.ok(!targetEvent.called, 'add event should not be called since it is disabled');
assert.equal(testObject.visibleViewDescriptors.length, 0);
assert.equal(target.elements.length, 0);
});
});