Skip to content
This repository has been archived by the owner on Mar 22, 2024. It is now read-only.

Commit

Permalink
EditorAppBase no longer inherits code from derived classes
Browse files Browse the repository at this point in the history
  • Loading branch information
kaisalmen committed Oct 7, 2023
1 parent 9c4bff5 commit 49982eb
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 122 deletions.
2 changes: 1 addition & 1 deletion packages/monaco-editor-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import { MonacoEditorReactComp } from '@typefox/monaco-editor-react/bundle';

These are the examples specifically for `@typefox/monaco-editor-react` that you can find in the repository:

- TypeScript editor worker using classical configuration [see](../examples/react_ts.html)
- TypeScript editor worker using classic configuration [see](../examples/react_ts.html)
- Langium statemachine language client and web worker based language server using the exact same user configuration as [wrapper statemachine](../examples/wrapper_statemachine.html), [see](../examples/react_statemachine.html)
- Langium grammar language client and web worker based language server using vscode-api configuration [see](../examples/react_langium.html)

Expand Down
33 changes: 15 additions & 18 deletions packages/monaco-editor-react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EditorAppClassic, MonacoEditorLanguageClientWrapper, UserConfig, WorkerConfigDirect, WorkerConfigOptions, isAppConfigDifferent } from 'monaco-editor-wrapper';
import { EditorAppClassic, EditorAppExtended, MonacoEditorLanguageClientWrapper, UserConfig, WorkerConfigDirect, WorkerConfigOptions } from 'monaco-editor-wrapper';
import { IDisposable } from 'monaco-editor';
import * as vscode from 'vscode';
import React, { CSSProperties } from 'react';
Expand Down Expand Up @@ -41,6 +41,8 @@ export class MonacoEditorReactComp extends React.Component<MonacoEditorProps> {
}

let mustReInit = false;
const prevConfig = prevProps.userConfig.wrapperConfig.editorAppConfig;
const config = userConfig.wrapperConfig.editorAppConfig;
const prevWorkerOptions = prevProps.userConfig.languageClientConfig?.options;
const currentWorkerOptions = userConfig.languageClientConfig?.options;
const prevIsWorker = (prevWorkerOptions?.$type === 'WorkerDirect');
Expand All @@ -59,26 +61,21 @@ export class MonacoEditorReactComp extends React.Component<MonacoEditorProps> {
mustReInit = true;
}

if (prevConfig.$type === 'classic' && config.$type === 'classic') {
mustReInit = (wrapper?.getMonacoEditorApp() as EditorAppClassic).isAppConfigDifferent(prevConfig, config, false) === true;
} else if (prevConfig.$type === 'extended' && config.$type === 'extended') {
mustReInit = (wrapper?.getMonacoEditorApp() as EditorAppExtended).isAppConfigDifferent(prevConfig, config, false) === true;
}

if (mustReInit) {
await this.handleReinit();
} else {
if (wrapper !== null) {
const prevConfig = prevProps.userConfig.wrapperConfig.editorAppConfig;
const config = userConfig.wrapperConfig.editorAppConfig;
const appConfigDifferent = isAppConfigDifferent(prevConfig, config, false, false);

// we need to restart if the editor wrapper config changed
if (appConfigDifferent) {
await this.handleReinit();
} else {
// the function now ensure a model update is only required if something else than the code changed
this.wrapper.updateModel(userConfig.wrapperConfig.editorAppConfig);

if (prevConfig.$type === 'classic' && config.$type === 'classic') {
if (prevConfig.editorOptions !== config.editorOptions) {
(wrapper.getMonacoEditorApp() as EditorAppClassic).updateMonacoEditorOptions(config.editorOptions ?? {});
}
}
// the function now ensure a model update is only required if something else than the code changed
this.wrapper.updateModel(userConfig.wrapperConfig.editorAppConfig);

if (prevConfig.$type === 'classic' && config.$type === 'classic') {
if (prevConfig.editorOptions !== config.editorOptions) {
(wrapper.getMonacoEditorApp() as EditorAppClassic).updateMonacoEditorOptions(config.editorOptions ?? {});
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/monaco-editor-wrapper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ All notable changes to npm module [monaco-editor-wrapper](https://www.npmjs.com/
- Use global configuration object that is passed to the wrapper on start
- The `monaco-editor-wrapper` and the new `@typefox/monaco-editor-react` component use the same configuration
- The underlying monaco-editor can be configured in two ways now (wrapperConfig):
- Classical: As before, but with one config object
- Classic: As before, but with one config object
- Extension like: Using the extension based mechanism supplied by `monaco-vscode-api`
- `monaco-languageclient` no longer exposes its own service. Now, we fully rely on services supplied by `monaco-vscode-api`
- This means even if you decide to configure monaco-editor the classical way, you still require some basic services. This configuration is made inside `MonacoEditorLanguageClientWrapper`. Potential serviceConfig supplied when using vscode-api extension config is taken into account and combined then.
Expand Down
10 changes: 5 additions & 5 deletions packages/monaco-editor-wrapper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The `UserConfig` now contains everything and is passed to the `start` function o
[@codingame/monaco-vscode-api](https://github.com/CodinGame/monaco-vscode-api) implements the VSCode api and redirects calls to `monaco-editor`. It allows to add serivccs that are usually only available in VSCode and not with pure `monaco-editor`.
`UserConfig` allows two possible configuration modes:

- **Classical**: Configure `monaco-editor` as you would when using it directly, [see](./src/editorAppClassic.ts)
- **Classic**: Configure `monaco-editor` as you would when using it directly, [see](./src/editorAppClassic.ts)
- **Extended**: Configure `monaco-editor` like a VSCode extension, [see](./src/editorAppExtended.ts)

[This](https://github.com/CodinGame/monaco-vscode-api#monaco-standalone-services) is the list of services defined by [@codingame/monaco-vscode-api](https://github.com/CodinGame/monaco-vscode-api).
Expand All @@ -46,7 +46,7 @@ The following services are enabled by default in both editor modes:

If you want any further services than the ones initialized by default, you should use the **extended** mode as some service (like *theme* and *textmate*) are incompatible with the **classic** mode.

Monarch grammars and themes can only be used in **classical** mode and textmate grammars and themes can only be used in **extended** mode.
Monarch grammars and themes can only be used in **classic** mode and textmate grammars and themes can only be used in **extended** mode.

## Usage

Expand Down Expand Up @@ -87,8 +87,8 @@ const run = async () => {

These are the examples specifically for `monaco-editor-wrapper` you find in the repository:

- TypeScript editor worker using classical mode, [see](../examples/wrapper_ts.html)
- TypeScript editor worker using classic mode, [see](../examples/wrapper_ts.html)
- Language client & web socket language server example using extended mode [see](../examples/wrapper_ws.html) It requires the json language server to run. Use `start:server:json` from [here](../examples/package.json)
- Multiple editors using classical mode [see](../examples/wrapper_adv.html)
- Multiple editors using classic mode [see](../examples/wrapper_adv.html)
- Langium statemachine language client and web worker based language server using extended mode [see](../examples/wrapper_statemachine.html)
- Langium grammar language client and web worker based language server allowing to choose classical or extended mode [see](../examples/wrapper_langium.html)
- Langium grammar language client and web worker based language server allowing to choose classic or extended mode [see](../examples/wrapper_langium.html)
75 changes: 20 additions & 55 deletions packages/monaco-editor-wrapper/src/editorAppBase.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { editor, Uri } from 'monaco-editor';
import { createConfiguredEditor, createConfiguredDiffEditor, createModelReference, ITextFileEditorModel } from 'vscode/monaco';
import { IReference } from 'vscode/service-override/editor';
import { WrapperConfig } from './wrapper.js';
import { updateUserConfiguration as vscodeUpdateUserConfiguration } from 'vscode/service-override/configuration';
import { EditorAppConfigClassic } from './editorAppClassic.js';
import { EditorAppConfigExtended } from './editorAppExtended.js';

export type ModelUpdate = {
languageId: string;
Expand All @@ -14,14 +11,21 @@ export type ModelUpdate = {
codeOriginalUri?: string;
}

export type EditorAppBaseConfig = ModelUpdate & {
export type EditorAppType = 'extended' | 'classic';

export type EditorAppConfigBase = ModelUpdate & {
$type: EditorAppType;
useDiffEditor: boolean;
domReadOnly?: boolean;
readOnly?: boolean;
awaitExtensionReadiness?: Array<() => Promise<void>>;
}

export type EditorAppType = 'extended' | 'classic';
export enum ModelUpdateType {
none,
code,
model
}

/**
* This is the base class for both Monaco Ediotor Apps:
Expand All @@ -44,8 +48,9 @@ export abstract class EditorAppBase {
this.id = id;
}

protected buildConfig(userAppConfig: EditorAppConfigExtended | EditorAppConfigClassic): EditorAppBaseConfig {
protected buildConfig(userAppConfig: EditorAppConfigBase): EditorAppConfigBase {
return {
$type: userAppConfig.$type,
languageId: userAppConfig.languageId,
code: userAppConfig.code ?? '',
codeOriginal: userAppConfig.codeOriginal ?? '',
Expand Down Expand Up @@ -214,31 +219,31 @@ export abstract class EditorAppBase {
return Promise.resolve();
}

protected async updateUserConfiguration(json?: string) {
updateMonacoEditorOptions(options: editor.IEditorOptions & editor.IGlobalEditorOptions) {
this.getEditor()?.updateOptions(options);
}

async updateUserConfiguration(json?: string) {
if (json) {
return vscodeUpdateUserConfiguration(json);
}
return Promise.resolve();
}

abstract getAppType(): string;
abstract init(): Promise<void>;
abstract specifyService(): editor.IEditorOverrideServices;
abstract createEditors(container: HTMLElement): Promise<void>;
abstract getConfig(): EditorAppConfigClassic | EditorAppConfigExtended;
abstract getConfig(): EditorAppConfigBase;
abstract disposeApp(): void;
abstract isAppConfigDifferent(orgConfig: EditorAppConfigBase, config: EditorAppConfigBase, includeModelData: boolean): boolean;
}

export const isExtendedEditorApp = (wrapperConfig: WrapperConfig) => {
return wrapperConfig.editorAppConfig?.$type === 'extended';
};

export const isCodeUpdateRequired = (config: EditorAppBaseConfig, modelUpdate: ModelUpdate) => {
export const isCodeUpdateRequired = (config: EditorAppConfigBase, modelUpdate: ModelUpdate) => {
const updateRequired = (modelUpdate.code !== undefined && modelUpdate.code !== config.code) || modelUpdate.codeOriginal !== config.codeOriginal;
return updateRequired ? ModelUpdateType.code : ModelUpdateType.none;
};

export const isModelUpdateRequired = (config: EditorAppBaseConfig, modelUpdate: ModelUpdate): ModelUpdateType => {
export const isModelUpdateRequired = (config: EditorAppConfigBase, modelUpdate: ModelUpdate): ModelUpdateType => {
const codeUpdate = isCodeUpdateRequired(config, modelUpdate);

type ModelUpdateKeys = keyof typeof modelUpdate;
Expand All @@ -249,43 +254,3 @@ export const isModelUpdateRequired = (config: EditorAppBaseConfig, modelUpdate:
const updateRequired = propsModelUpdate.some(propCompare);
return updateRequired ? ModelUpdateType.model : codeUpdate;
};

export enum ModelUpdateType {
none,
code,
model
}

export const isAppConfigDifferent = (orgConfig: EditorAppConfigClassic | EditorAppConfigExtended,
config: EditorAppConfigClassic | EditorAppConfigExtended, includeModelData: boolean, includeEditorOptions: boolean): boolean => {

let different = includeModelData ? isModelUpdateRequired(orgConfig, config) !== ModelUpdateType.none : false;
if (orgConfig.$type === config.$type) {

type ClassicKeys = keyof typeof orgConfig;
const propsClassic = ['useDiffEditor', 'readOnly', 'domReadOnly', 'awaitExtensionReadiness', 'automaticLayout', 'languageDef', 'languageExtensionConfig', 'theme', 'themeData'];
const propsClassicEditorOptions = ['editorOptions', 'diffEditorOptions'];

const propCompareClassic = (name: string) => {
return orgConfig[name as ClassicKeys] !== config[name as ClassicKeys];
};

const propsVscode = ['useDiffEditor', 'readOnly', 'domReadOnly', 'awaitExtensionReadiness', 'userConfiguration', 'extensions'];
type ExtendedKeys = keyof typeof orgConfig;
const propCompareExtended = (name: string) => {
return orgConfig[name as ExtendedKeys] !== config[name as ExtendedKeys];
};

if (orgConfig.$type === 'classic' && config.$type === 'classic') {
different = different || propsClassic.some(propCompareClassic);
if (includeEditorOptions) {
different = different || propsClassicEditorOptions.some(propCompareClassic);
}
} else if (orgConfig.$type === 'extended' && config.$type === 'extended') {
different = different || propsVscode.some(propCompareExtended);
}
} else {
throw new Error('Provided configurations are not of the same type.');
}
return different;
};
30 changes: 20 additions & 10 deletions packages/monaco-editor-wrapper/src/editorAppClassic.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { editor, languages } from 'monaco-editor';
import { EditorAppBase, EditorAppBaseConfig, EditorAppType } from './editorAppBase.js';
import { EditorAppBase, EditorAppConfigBase, ModelUpdateType, isModelUpdateRequired } from './editorAppBase.js';
import { UserConfig } from './wrapper.js';
import { Logger } from './logger.js';

export type EditorAppConfigClassic = EditorAppBaseConfig & {
export type EditorAppConfigClassic = EditorAppConfigBase & {
$type: 'classic';
automaticLayout?: boolean;
theme?: editor.BuiltinTheme | string;
Expand Down Expand Up @@ -43,10 +43,6 @@ export class EditorAppClassic extends EditorAppBase {
this.config.themeData = userAppConfig.themeData ?? undefined;
}

getAppType(): EditorAppType {
return 'classic';
}

getConfig(): EditorAppConfigClassic {
return this.config;
}
Expand Down Expand Up @@ -102,12 +98,26 @@ export class EditorAppClassic extends EditorAppBase {
this.logger?.info('Init of Classic App was completed.');
}

updateMonacoEditorOptions(options: editor.IEditorOptions & editor.IGlobalEditorOptions) {
this.getEditor()?.updateOptions(options);
}

disposeApp(): void {
this.disposeEditor();
this.disposeDiffEditor();
}

isAppConfigDifferent(orgConfig: EditorAppConfigClassic, config: EditorAppConfigClassic, includeModelData: boolean): boolean {
let different = false;
if (includeModelData) {
different = isModelUpdateRequired(orgConfig, config) !== ModelUpdateType.none;
}
type ClassicKeys = keyof typeof orgConfig;
const propsClassic = ['useDiffEditor', 'readOnly', 'domReadOnly', 'awaitExtensionReadiness', 'automaticLayout', 'languageDef', 'languageExtensionConfig', 'theme', 'themeData'];
const propsClassicEditorOptions = ['editorOptions', 'diffEditorOptions'];

const propCompareClassic = (name: string) => {
return orgConfig[name as ClassicKeys] !== config[name as ClassicKeys];
};

different = different || propsClassic.some(propCompareClassic);
different = different || propsClassicEditorOptions.some(propCompareClassic);
return different;
}
}
22 changes: 16 additions & 6 deletions packages/monaco-editor-wrapper/src/editorAppExtended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IDisposable, editor } from 'monaco-editor';
import getThemeServiceOverride from '@codingame/monaco-vscode-theme-service-override';
import getTextmateServiceOverride from '@codingame/monaco-vscode-textmate-service-override';
import { whenReady as whenReadyTheme } from '@codingame/monaco-vscode-theme-defaults-default-extension';
import { EditorAppBase, EditorAppBaseConfig, EditorAppType } from './editorAppBase.js';
import { EditorAppBase, EditorAppConfigBase, ModelUpdateType, isModelUpdateRequired } from './editorAppBase.js';
import { registerExtension, IExtensionManifest, ExtensionHostKind } from 'vscode/extensions';
import { UserConfig } from './wrapper.js';
import { verifyUrlorCreateDataUrl } from './utils.js';
Expand All @@ -18,7 +18,7 @@ export type UserConfiguration = {
json?: string;
}

export type EditorAppConfigExtended = EditorAppBaseConfig & {
export type EditorAppConfigExtended = EditorAppConfigBase & {
$type: 'extended';
extensions?: ExtensionConfig[];
userConfiguration?: UserConfiguration;
Expand Down Expand Up @@ -57,10 +57,6 @@ export class EditorAppExtended extends EditorAppBase {
this.config.userConfiguration = userAppConfig.userConfiguration ?? undefined;
}

getAppType(): EditorAppType {
return 'extended';
}

getConfig(): EditorAppConfigExtended {
return this.config;
}
Expand Down Expand Up @@ -116,4 +112,18 @@ export class EditorAppExtended extends EditorAppBase {
this.disposeDiffEditor();
this.extensionRegisterResults.forEach((k) => k?.dispose());
}

isAppConfigDifferent(orgConfig: EditorAppConfigExtended, config: EditorAppConfigExtended, includeModelData: boolean): boolean {
let different = false;
if (includeModelData) {
different = isModelUpdateRequired(orgConfig, config) !== ModelUpdateType.none;
}
const propsExtended = ['useDiffEditor', 'readOnly', 'domReadOnly', 'awaitExtensionReadiness', 'userConfiguration', 'extensions'];
type ExtendedKeys = keyof typeof orgConfig;
const propCompareExtended = (name: string) => {
return orgConfig[name as ExtendedKeys] !== config[name as ExtendedKeys];
};
different = different || propsExtended.some(propCompareExtended);
return different;
}
}
10 changes: 3 additions & 7 deletions packages/monaco-editor-wrapper/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import {
EditorAppBase,
isExtendedEditorApp,
isCodeUpdateRequired,
isModelUpdateRequired,
isAppConfigDifferent,
ModelUpdateType
} from './editorAppBase.js';

import type {
EditorAppBaseConfig,
EditorAppConfigBase,
EditorAppType,
ModelUpdate
} from './editorAppBase.js';
Expand All @@ -18,7 +16,7 @@ import type {
} from './editorAppClassic.js';

import {
EditorAppClassic,
EditorAppClassic
} from './editorAppClassic.js';

import type {
Expand Down Expand Up @@ -67,7 +65,7 @@ import {

export type {
WrapperConfig,
EditorAppBaseConfig,
EditorAppConfigBase,
EditorAppType,
EditorAppConfigClassic,
ExtensionConfig,
Expand All @@ -92,10 +90,8 @@ export {
MonacoEditorLanguageClientWrapper,
LanguageClientWrapper,
EditorAppBase,
isExtendedEditorApp,
isCodeUpdateRequired,
isModelUpdateRequired,
isAppConfigDifferent,
ModelUpdateType,
EditorAppClassic,
EditorAppExtended,
Expand Down
Loading

0 comments on commit 49982eb

Please sign in to comment.