mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode 27ada910e121e23a6d95ecca9cae595fb98ab568
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -254,4 +254,6 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
||||
|
||||
return extensionHostDebugEnvironment;
|
||||
}
|
||||
|
||||
get skipReleaseNotes(): boolean { return false; }
|
||||
}
|
||||
|
||||
@@ -28,4 +28,6 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
|
||||
readonly webviewExternalEndpoint: string;
|
||||
readonly webviewResourceRoot: string;
|
||||
readonly webviewCspSource: string;
|
||||
|
||||
readonly skipReleaseNotes: boolean;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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[]> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -59,6 +59,7 @@ export interface ISetting {
|
||||
overrides?: ISetting[];
|
||||
overrideOf?: ISetting;
|
||||
deprecationMessage?: string;
|
||||
deprecationMessageIsMarkdown?: boolean;
|
||||
|
||||
scope?: ConfigurationScope;
|
||||
type?: string | string[];
|
||||
|
||||
@@ -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)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 { }
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user