Skip to content

Commit

Permalink
[monaco] Align ConfigurationChangeEvent with VS Code
Browse files Browse the repository at this point in the history
Also-by: Roman Nikitenko <rnikiten@redhat.com>
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>
  • Loading branch information
akosyakov committed Aug 21, 2020
1 parent c7df31a commit 1dde8d9
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 40 deletions.
119 changes: 90 additions & 29 deletions packages/monaco/src/browser/monaco-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ import '../../src/browser/style/index.css';
import '../../src/browser/style/symbol-sprite.svg';
import '../../src/browser/style/symbol-icons.css';

import debounce = require('lodash.debounce');
import { ContainerModule, decorate, injectable, interfaces } from 'inversify';
import { MenuContribution, CommandContribution } from '@theia/core/lib/common';
import { PreferenceScope } from '@theia/core/lib/common/preferences/preference-scope';
import {
QuickOpenService, FrontendApplicationContribution, KeybindingContribution,
PreferenceService, PreferenceSchemaProvider, createPreferenceProxy, QuickOpenContribution, PreferenceChanges
PreferenceService, PreferenceSchemaProvider, createPreferenceProxy, QuickOpenContribution, PreferenceScope, PreferenceChange, OVERRIDE_PROPERTY_PATTERN
} from '@theia/core/lib/browser';
import { TextEditorProvider, DiffNavigatorProvider } from '@theia/editor/lib/browser';
import { StrictEditorTextFocusContext } from '@theia/editor/lib/browser/editor-keybinding-contexts';
Expand Down Expand Up @@ -149,7 +147,7 @@ export function createMonacoConfigurationService(container: interfaces.Container
const service = monaco.services.StaticServices.configurationService.get();
const _configuration = service._configuration;

_configuration.getValue = (section, overrides, workspace) => {
_configuration.getValue = (section, overrides) => {
const overrideIdentifier = overrides && 'overrideIdentifier' in overrides && overrides['overrideIdentifier'] as string || undefined;
const resourceUri = overrides && 'resource' in overrides && !!overrides['resource'] && overrides['resource'].toString();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -162,40 +160,103 @@ export function createMonacoConfigurationService(container: interfaces.Container
return proxy;
};

const initFromConfiguration = debounce(() => {
const event = new monaco.services.ConfigurationChangeEvent();
event._source = 6 /* DEFAULT */;
service._onDidChangeConfiguration.fire(event);
});
preferences.onPreferenceChanged(e => {
if (e.scope === PreferenceScope.Default) {
initFromConfiguration();
const toTarget = (scope: PreferenceScope): monaco.services.ConfigurationTarget => {
switch (scope) {
case PreferenceScope.Default: return monaco.services.ConfigurationTarget.DEFAULT;
case PreferenceScope.User: return monaco.services.ConfigurationTarget.USER;
case PreferenceScope.Workspace: return monaco.services.ConfigurationTarget.WORKSPACE;
case PreferenceScope.Folder: return monaco.services.ConfigurationTarget.WORKSPACE_FOLDER;
}
};

interface FireDidChangeConfigurationContext {
changes: PreferenceChange[];
affectedKeys: Set<string>;
keys: Set<string>;
overrides: Map<string, Set<string>>
}
const newFireDidChangeConfigurationContext = (): FireDidChangeConfigurationContext => ({
changes: [],
affectedKeys: new Set<string>(),
keys: new Set<string>(),
overrides: new Map<string, Set<string>>()
});
const parseSections = (changes?: PreferenceChanges) => {
if (!changes) {
return undefined;
const fireDidChangeConfiguration = (source: monaco.services.ConfigurationTarget, context: FireDidChangeConfigurationContext): void => {
if (!context.affectedKeys.size) {
return;
}
const sections = [];
for (let key of Object.keys(changes)) {
const hasOverride = key.startsWith('[');
const overrides: [string, string[]][] = [];
for (const [override, values] of context.overrides) {
overrides.push([override, [...values]]);
}
service._onDidChangeConfiguration.fire({
change: {
keys: [...context.keys],
overrides
},
affectedKeys: [...context.affectedKeys],
source,
affectsConfiguration: (prefix, options) => {
if (!context.affectedKeys.has(prefix)) {
return false;
}
for (const change of context.changes) {
const overridden = preferences.overriddenPreferenceName(change.preferenceName);
const preferenceName = overridden ? overridden.preferenceName : change.preferenceName;
if (preferenceName.startsWith(prefix)) {
if (options?.overrideIdentifier !== undefined) {
if (overridden && overridden.overrideIdentifier !== options?.overrideIdentifier) {
continue;
}
}
if (change.affects(options?.resource?.toString())) {
return true;
}
}
}
return false;
}
});
};

preferences.onPreferencesChanged(event => {
let source: monaco.services.ConfigurationTarget | undefined;
let context = newFireDidChangeConfigurationContext();
for (let key of Object.keys(event)) {
const change = event[key];
const target = toTarget(change.scope);
if (source !== undefined && target !== source) {
fireDidChangeConfiguration(source, context);
context = newFireDidChangeConfigurationContext();
}
context.changes.push(change);
source = target;

let overrideKeys: Set<string> | undefined;
if (key.startsWith('[')) {
const index = key.indexOf('.');
const override = key.substring(0, index);
const overrideIdentifier = override.match(OVERRIDE_PROPERTY_PATTERN)?.[1];
if (overrideIdentifier) {
context.keys.add(override);
context.affectedKeys.add(override);
overrideKeys = context.overrides.get(overrideIdentifier) || new Set<string>();
context.overrides.set(overrideIdentifier, overrideKeys);
key = key.substring(index + 1);
}
}
while (key) {
sections.push(key);
if (hasOverride && key.indexOf('.') !== -1) {
sections.push(key.substr(key.indexOf('.')));
if (overrideKeys) {
overrideKeys.add(key);
}
context.keys.add(key);
context.affectedKeys.add(key);
const index = key.lastIndexOf('.');
key = key.substring(0, index);
}
}
return sections;
};
preferences.onPreferencesChanged((changes?: PreferenceChanges) => {
const affectedSections = parseSections(changes);
if (affectedSections) {
const event = new monaco.services.ConfigurationChangeEvent();
event.change(affectedSections);
service._onDidChangeConfiguration.fire(event);
if (source) {
fireDidChangeConfiguration(source, context);
}
});

Expand Down
46 changes: 35 additions & 11 deletions packages/monaco/src/typings/monaco/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -640,23 +640,47 @@ declare module monaco.services {
// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/platform/configuration/common/configurationModels.ts#L337
export interface Configuration {
getValue(section: string | undefined, overrides: any, workspace: any | undefined): any;
toData(): any;
}

//*************** todo: align ConfigurationChangeEvent with VS Code *************
export class ConfigurationChangeEvent {
// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/platform/configuration/common/configuration.ts#L30-L37
_source?: number;
// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/platform/configuration/common/configuration.ts#L30-L37
export const enum ConfigurationTarget {
USER = 1,
USER_LOCAL,
USER_REMOTE,
WORKSPACE,
WORKSPACE_FOLDER,
DEFAULT,
MEMORY
}

// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/platform/configuration/common/configuration.ts#L51
export interface IConfigurationChange {
keys: string[];
overrides: [string, string[]][];
}

// https://github.com/theia-ide/vscode/blob/b0b47123a5da83d42c2675f2bfff5bb9f1b2673c/src/vs/platform/configuration/common/configuration.ts#L56
export class IConfigurationChangeEvent {

readonly source: ConfigurationTarget;
readonly affectedKeys: string[];
readonly change: IConfigurationChange;

// https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/platform/configuration/common/configurationModels.ts#L620
change(keys: string[]): ConfigurationChangeEvent;
affectsConfiguration(configuration: string, overrides?: IConfigurationOverrides): boolean;
}

// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/platform/configuration/common/configuration.ts#L25
export interface IConfigurationOverrides {
overrideIdentifier?: string | null;
resource?: monaco.Uri | null;
}

// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/editor/standalone/browser/simpleServices.ts#L434
export interface IConfigurationService {
_onDidChangeConfiguration: monaco.Emitter<ConfigurationChangeEvent>;
_onDidChangeConfiguration: monaco.Emitter<IConfigurationChangeEvent>;
_configuration: Configuration;
}
//*************** todo: align ConfigurationChangeEvent with VS Code *************

// https://github.com/microsoft/vscode/blob/standalone/0.20.x/src/vs/editor/common/services/textResourceConfigurationService.ts#L71
export interface ITextResourcePropertiesService {
Expand Down Expand Up @@ -769,9 +793,9 @@ declare module monaco.services {
}

// https://github.com/microsoft/vscode/blob/standalone/0.20.x/src/vs/editor/common/services/editorWorkerService.ts#L21
export interface IEditorWorkerService {
computeMoreMinimalEdits(resource: monaco.Uri, edits: monaco.languages.TextEdit[] | null | undefined): Promise<monaco.languages.TextEdit[] | undefined>;
}
export interface IEditorWorkerService {
computeMoreMinimalEdits(resource: monaco.Uri, edits: monaco.languages.TextEdit[] | null | undefined): Promise<monaco.languages.TextEdit[] | undefined>;
}

// https://github.com/theia-ide/vscode/blob/standalone/0.20.x/src/vs/editor/standalone/browser/standaloneServices.ts#L56
export module StaticServices {
Expand Down

0 comments on commit 1dde8d9

Please sign in to comment.