diff --git a/packages/examples/src/reactTs.tsx b/packages/examples/src/reactTs.tsx
index eaba6fc..6d3e4c3 100644
--- a/packages/examples/src/reactTs.tsx
+++ b/packages/examples/src/reactTs.tsx
@@ -1,5 +1,5 @@
-import React from 'react';
import ReactDOM from 'react-dom/client';
+import React, { useState } from 'react';
import { MonacoEditorReactComp } from '@typefox/monaco-editor-react';
import { UserConfig } from 'monaco-editor-wrapper';
@@ -9,38 +9,55 @@ import 'monaco-editor/esm/vs/language/typescript/monaco.contribution.js';
import { buildWorkerDefinition } from 'monaco-editor-workers';
buildWorkerDefinition('../../../../node_modules/monaco-editor-workers/dist/workers', import.meta.url, false);
-const rootElem = document.getElementById('root')!;
-const userConfig: UserConfig = {
- htmlElement: rootElem,
- wrapperConfig: {
- serviceConfig: {
- enableKeybindingsService: true,
- debugLogging: true
- },
- editorAppConfig: {
- $type: 'classic',
- languageId: 'typescript',
- useDiffEditor: false,
- theme: 'vs-dark',
- code: `function sayHello(): string {
- return "Hello";
-};`
+const EditorDemo: React.FC = () => {
+ const logMessage = 'console.log(\'hello\')';
+ const [content, setContent] = useState(logMessage);
+
+ const rootElem = document.getElementById('root')!;
+ const userConfig: UserConfig = {
+ htmlElement: rootElem,
+ wrapperConfig: {
+ serviceConfig: {
+ enableKeybindingsService: true,
+ debugLogging: true
+ },
+ editorAppConfig: {
+ $type: 'classic',
+ languageId: 'typescript',
+ useDiffEditor: false,
+ theme: 'vs-dark',
+ code: content
+ }
}
- }
-};
+ };
-const onTextChanged = (text: string, isDirty: boolean) => {
- console.log(`Dirty? ${isDirty} Content: ${text}`);
-};
+ const addConsoleMessage = () => {
+ setContent(`${content}\n${logMessage}`);
+ };
-const comp = ;
+ const onTextChanged = (text: string, isDirty: boolean) => {
+ console.log(`Dirty? ${isDirty} Content: ${text}`);
+ };
+ return (
+ <>
+
+
+ >
+
+ );
+};
+
+const comp = ;
+const rootElem = document.getElementById('root')!;
const root = ReactDOM.createRoot(rootElem);
root.render(comp);
diff --git a/packages/examples/src/wrapperTs.ts b/packages/examples/src/wrapperTs.ts
index 97304cd..f2c05e5 100644
--- a/packages/examples/src/wrapperTs.ts
+++ b/packages/examples/src/wrapperTs.ts
@@ -60,13 +60,13 @@ try {
if (wrapper.getMonacoEditorApp()?.getConfig().codeUri === codeUri) {
updateModel({
code: codeOriginal,
- uri: codeOriginalUri,
+ codeUri: codeOriginalUri,
languageId: 'typescript',
});
} else {
updateModel({
code: code,
- uri: codeUri,
+ codeUri: codeUri,
languageId: 'typescript',
});
}
diff --git a/packages/monaco-editor-react/src/index.tsx b/packages/monaco-editor-react/src/index.tsx
index 23dd17d..9eaa628 100644
--- a/packages/monaco-editor-react/src/index.tsx
+++ b/packages/monaco-editor-react/src/index.tsx
@@ -1,4 +1,4 @@
-import { EditorAppClassic, EditorAppConfigClassic, MonacoEditorLanguageClientWrapper, UserConfig, WorkerConfigDirect, WorkerConfigOptions } from 'monaco-editor-wrapper';
+import { EditorAppClassic, MonacoEditorLanguageClientWrapper, UserConfig, WorkerConfigDirect, WorkerConfigOptions, isAppConfigDifferent } from 'monaco-editor-wrapper';
import { IDisposable } from 'monaco-editor';
import * as vscode from 'vscode';
import React, { CSSProperties } from 'react';
@@ -63,37 +63,23 @@ export class MonacoEditorReactComp extends React.Component {
await this.handleReinit();
} else {
if (wrapper !== null) {
- let restarted = false;
+ 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 (prevProps.userConfig.wrapperConfig.editorAppConfig !==
- userConfig.wrapperConfig.editorAppConfig) {
- restarted = true;
+ 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 (!restarted) {
- const appConfig = userConfig.wrapperConfig.editorAppConfig;
- if (appConfig.$type === 'classic') {
- const options = (appConfig as EditorAppConfigClassic).editorOptions;
- const prevOptions = (prevProps.userConfig.wrapperConfig.editorAppConfig as EditorAppConfigClassic).editorOptions;
- if (options !== prevOptions && options !== undefined) {
- (wrapper.getMonacoEditorApp() as EditorAppClassic).updateMonacoEditorOptions(options);
+ if (prevConfig.$type === 'classic' && config.$type === 'classic') {
+ if (prevConfig.editorOptions !== config.editorOptions) {
+ (wrapper.getMonacoEditorApp() as EditorAppClassic).updateMonacoEditorOptions(config.editorOptions ?? {});
}
}
-
- const languageId = appConfig.languageId;
- const code = appConfig.code;
- const prevLanguageId = prevProps.userConfig.wrapperConfig.editorAppConfig.languageId;
- const prevCode = prevProps.userConfig.wrapperConfig.editorAppConfig.code;
- if (languageId !== prevLanguageId && code !== prevCode) {
- this.wrapper.updateModel({
- languageId: languageId,
- code: code
- });
- }
}
-
}
}
}
diff --git a/packages/monaco-editor-wrapper/src/editorAppBase.ts b/packages/monaco-editor-wrapper/src/editorAppBase.ts
index 611b730..9d92381 100644
--- a/packages/monaco-editor-wrapper/src/editorAppBase.ts
+++ b/packages/monaco-editor-wrapper/src/editorAppBase.ts
@@ -1,18 +1,21 @@
import { editor, Uri } from 'monaco-editor';
import { createConfiguredEditor, createConfiguredDiffEditor, createModelReference, ITextFileEditorModel } from 'vscode/monaco';
import { IReference } from 'vscode/service-override/editor';
-import { updateUserConfiguration as vscodeUpdateUserConfiguratio } from 'vscode/service-override/configuration';
-import { ModelUpdate, UserConfig, WrapperConfig } from './wrapper.js';
+import { UserConfig, WrapperConfig } from './wrapper.js';
+import { updateUserConfiguration as vscodeUpdateUserConfiguration } from 'vscode/service-override/configuration';
import { EditorAppConfigClassic } from './editorAppClassic.js';
import { EditorAppConfigVscodeApi } from './editorAppVscodeApi.js';
-export type EditorAppBaseConfig = {
+export type ModelUpdate = {
languageId: string;
- code: string;
+ code?: string;
codeUri?: string;
- useDiffEditor: boolean;
codeOriginal?: string;
codeOriginalUri?: string;
+}
+
+export type EditorAppBaseConfig = ModelUpdate & {
+ useDiffEditor: boolean;
domReadOnly?: boolean;
readOnly?: boolean;
userConfiguration?: UserConfiguration;
@@ -114,8 +117,21 @@ export abstract class EditorAppBase {
return Promise.reject(new Error('You cannot update the editor model, because the regular editor is not configured.'));
}
- this.updateAppConfig(modelUpdate);
- await this.updateEditorModel();
+ const modelUpdateType = isModelUpdateRequired(this.getConfig(), modelUpdate);
+
+ if (modelUpdateType === ModelUpdateType.code) {
+ this.updateAppConfig(modelUpdate);
+ if (this.getConfig().useDiffEditor) {
+ this.diffEditor?.getModifiedEditor().setValue(modelUpdate.code ?? '');
+ this.diffEditor?.getOriginalEditor().setValue(modelUpdate.codeOriginal ?? '');
+ } else {
+ this.editor.setValue(modelUpdate.code ?? '');
+ }
+ } else if (modelUpdateType === ModelUpdateType.model) {
+ this.updateAppConfig(modelUpdate);
+ await this.updateEditorModel();
+ }
+ return Promise.resolve();
}
private async updateEditorModel(): Promise {
@@ -134,9 +150,11 @@ export abstract class EditorAppBase {
if (!this.diffEditor) {
return Promise.reject(new Error('You cannot update the diff editor models, because the diffEditor is not configured.'));
}
-
- this.updateAppConfig(modelUpdate);
- return this.updateDiffEditorModel();
+ if (isModelUpdateRequired(this.getConfig(), modelUpdate)) {
+ this.updateAppConfig(modelUpdate);
+ await this.updateDiffEditorModel();
+ }
+ return Promise.resolve();
}
private async updateDiffEditorModel(): Promise {
@@ -167,25 +185,11 @@ export abstract class EditorAppBase {
private updateAppConfig(modelUpdate: ModelUpdate) {
const config = this.getConfig();
- if (modelUpdate.code !== undefined) {
- config.code = modelUpdate.code;
- }
-
- if (modelUpdate.languageId !== undefined) {
- config.languageId = modelUpdate.languageId;
- }
-
- if (modelUpdate.uri !== undefined) {
- config.codeUri = modelUpdate.uri;
- }
-
- if (modelUpdate.codeOriginal !== undefined) {
- config.codeOriginal = modelUpdate.codeOriginal;
- }
-
- if (modelUpdate.codeOriginalUri !== undefined) {
- config.codeOriginalUri = modelUpdate.codeOriginalUri;
- }
+ config.languageId = modelUpdate.languageId;
+ config.code = modelUpdate.code;
+ config.codeUri = modelUpdate.codeUri;
+ config.codeOriginal = modelUpdate.codeOriginal;
+ config.codeOriginalUri = modelUpdate.codeOriginalUri;
}
getEditorUri(uriType: 'code' | 'codeOriginal') {
@@ -208,7 +212,7 @@ export abstract class EditorAppBase {
async updateUserConfiguration(config: UserConfiguration) {
if (config.json) {
- return vscodeUpdateUserConfiguratio(config.json);
+ return vscodeUpdateUserConfiguration(config.json);
}
return Promise.reject(new Error('Supplied config is undefined'));
}
@@ -223,3 +227,56 @@ export abstract class EditorAppBase {
export const isVscodeApiEditorApp = (wrapperConfig: WrapperConfig) => {
return wrapperConfig.editorAppConfig?.$type === 'vscodeApi';
};
+
+export const isCodeUpdateRequired = (config: EditorAppBaseConfig, modelUpdate: ModelUpdate) => {
+ let updateRequired = modelUpdate.code !== undefined && modelUpdate.code !== config.code;
+ updateRequired = updateRequired || modelUpdate.codeOriginal !== config.codeOriginal;
+ return updateRequired ? ModelUpdateType.code : ModelUpdateType.none;
+};
+
+export const isModelUpdateRequired = (config: EditorAppBaseConfig, modelUpdate: ModelUpdate): ModelUpdateType => {
+ const codeUpdate = isCodeUpdateRequired(config, modelUpdate);
+ let updateRequired = modelUpdate.languageId !== config.languageId;
+ updateRequired = updateRequired || modelUpdate.codeUri !== config.codeUri;
+ updateRequired = updateRequired || modelUpdate.codeOriginalUri !== config.codeOriginalUri;
+ return updateRequired ? ModelUpdateType.model : codeUpdate;
+};
+
+export enum ModelUpdateType {
+ none,
+ code,
+ model
+}
+
+export const isAppConfigDifferent = (orgConfig: EditorAppConfigClassic | EditorAppConfigVscodeApi,
+ config: EditorAppConfigClassic | EditorAppConfigVscodeApi, includeModelData: boolean, includeEditorOptions: boolean): boolean => {
+
+ // this is done by hand, ModelUpdate is only considered if flag is set
+ let different = includeModelData ? isModelUpdateRequired(orgConfig, config) !== ModelUpdateType.none : false;
+ if (orgConfig.$type === config.$type) {
+ if (orgConfig.$type === 'classic' && config.$type === 'classic') {
+ different = different || orgConfig.automaticLayout !== config.automaticLayout;
+ different = different || orgConfig.domReadOnly !== config.domReadOnly;
+ if (includeEditorOptions === true) {
+ different = different || orgConfig.diffEditorOptions !== config.diffEditorOptions;
+ different = different || orgConfig.editorOptions !== config.editorOptions;
+ }
+ different = different || orgConfig.languageDef !== config.languageDef;
+ different = different || orgConfig.languageExtensionConfig !== config.languageExtensionConfig;
+ different = different || orgConfig.readOnly !== config.readOnly;
+ different = different || orgConfig.theme !== config.theme;
+ different = different || orgConfig.themeData !== config.themeData;
+ different = different || orgConfig.useDiffEditor !== config.useDiffEditor;
+ } else if (orgConfig.$type === 'vscodeApi' && config.$type === 'vscodeApi') {
+ different = different || orgConfig.domReadOnly !== config.domReadOnly;
+ different = different || orgConfig.extension !== config.extension;
+ different = different || orgConfig.extensionFilesOrContents !== config.extensionFilesOrContents;
+ different = different || orgConfig.readOnly !== config.readOnly;
+ different = different || orgConfig.useDiffEditor !== config.useDiffEditor;
+ different = different || orgConfig.userConfiguration !== config.userConfiguration;
+ }
+ } else {
+ throw new Error('Provided configurations are not of the same type.');
+ }
+ return different;
+};
diff --git a/packages/monaco-editor-wrapper/src/index.ts b/packages/monaco-editor-wrapper/src/index.ts
index b6d7d95..a0a6377 100644
--- a/packages/monaco-editor-wrapper/src/index.ts
+++ b/packages/monaco-editor-wrapper/src/index.ts
@@ -1,11 +1,16 @@
import {
EditorAppBase,
- isVscodeApiEditorApp
+ isVscodeApiEditorApp,
+ isCodeUpdateRequired,
+ isModelUpdateRequired,
+ isAppConfigDifferent,
+ ModelUpdateType
} from './editorAppBase.js';
import type {
EditorAppBaseConfig,
EditorAppType,
+ ModelUpdate,
UserConfiguration,
} from './editorAppBase.js';
@@ -44,7 +49,6 @@ import {
import type {
UserConfig,
- ModelUpdate,
WrapperConfig
} from './wrapper.js';
@@ -87,6 +91,10 @@ export {
LanguageClientWrapper,
EditorAppBase,
isVscodeApiEditorApp,
+ isCodeUpdateRequired,
+ isModelUpdateRequired,
+ isAppConfigDifferent,
+ ModelUpdateType,
EditorAppClassic,
EditorAppVscodeApi,
Logger
diff --git a/packages/monaco-editor-wrapper/src/wrapper.ts b/packages/monaco-editor-wrapper/src/wrapper.ts
index 6a85004..1e242fc 100644
--- a/packages/monaco-editor-wrapper/src/wrapper.ts
+++ b/packages/monaco-editor-wrapper/src/wrapper.ts
@@ -2,7 +2,7 @@ import { editor } from 'monaco-editor';
import { initServices, wasVscodeApiInitialized, InitializeServiceConfig, MonacoLanguageClient } from 'monaco-languageclient';
import { EditorAppVscodeApi, EditorAppConfigVscodeApi } from './editorAppVscodeApi.js';
import { EditorAppClassic, EditorAppConfigClassic } from './editorAppClassic.js';
-import { UserConfiguration, isVscodeApiEditorApp } from './editorAppBase.js';
+import { ModelUpdate, UserConfiguration, isVscodeApiEditorApp } from './editorAppBase.js';
import { LanguageClientConfig, LanguageClientWrapper } from './languageClientWrapper.js';
import { Logger, LoggerConfig } from './logger.js';
@@ -19,14 +19,6 @@ export type UserConfig = {
languageClientConfig?: LanguageClientConfig;
}
-export type ModelUpdate = {
- languageId?: string;
- code?: string;
- uri?: string;
- codeOriginal?: string;
- codeOriginalUri?: string;
-}
-
/**
* This class is responsible for the overall ochestration.
* It inits, start and disposes the editor apps and the language client (if configured) and provides
diff --git a/packages/monaco-editor-wrapper/test/editorAppBase.test.ts b/packages/monaco-editor-wrapper/test/editorAppBase.test.ts
index 50d3bfa..eb10065 100644
--- a/packages/monaco-editor-wrapper/test/editorAppBase.test.ts
+++ b/packages/monaco-editor-wrapper/test/editorAppBase.test.ts
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';
-import { EditorAppClassic, isVscodeApiEditorApp } from 'monaco-editor-wrapper';
-import { createBaseConfig, createWrapperConfig } from './helper.js';
+import { isAppConfigDifferent, isVscodeApiEditorApp, isModelUpdateRequired, EditorAppClassic, ModelUpdateType } from 'monaco-editor-wrapper';
+import { createBaseConfig, createEditorAppConfig, createWrapperConfig } from './helper.js';
describe('Test EditorAppBase', () => {
@@ -36,4 +36,30 @@ describe('Test EditorAppBase', () => {
const app = new EditorAppClassic('config defaults', config);
expect(app.getConfig().userConfiguration?.json).toEqual('{ "editor.semanticHighlighting.enabled": true }');
});
+
+ test('isModelUpdateRequired', () => {
+ const config = createEditorAppConfig('classic');
+ let modelUpdateType = isModelUpdateRequired(config, { languageId: 'typescript', code: '' });
+ expect(modelUpdateType).toBe(ModelUpdateType.none);
+
+ modelUpdateType = isModelUpdateRequired(config, { languageId: 'typescript' });
+ expect(modelUpdateType).toBe(ModelUpdateType.none);
+
+ modelUpdateType = isModelUpdateRequired(config, { languageId: 'typescript', code: 'test' });
+ expect(modelUpdateType).toBe(ModelUpdateType.code);
+
+ modelUpdateType = isModelUpdateRequired(config, { languageId: 'javascript', code: 'test' });
+ expect(modelUpdateType).toBe(ModelUpdateType.model);
+ });
+
+ test('isModelUpdateRequired', () => {
+ const orgConfig = createEditorAppConfig('classic');
+ const config = createEditorAppConfig('classic');
+ expect(isAppConfigDifferent(orgConfig, config, false, false)).toBeFalsy();
+
+ config.code = 'test';
+ expect(isAppConfigDifferent(orgConfig, config, false, false)).toBeFalsy();
+ expect(isAppConfigDifferent(orgConfig, config, true, false)).toBeTruthy();
+ });
+
});
diff --git a/packages/monaco-editor-wrapper/test/helper.ts b/packages/monaco-editor-wrapper/test/helper.ts
index 7b552be..6fb42f7 100644
--- a/packages/monaco-editor-wrapper/test/helper.ts
+++ b/packages/monaco-editor-wrapper/test/helper.ts
@@ -15,11 +15,15 @@ export const createBaseConfig = (type: EditorAppType): UserConfig => {
export const createWrapperConfig = (type: EditorAppType) => {
return {
- editorAppConfig: {
- $type: type,
- languageId: 'typescript',
- code: '',
- useDiffEditor: false,
- }
+ editorAppConfig: createEditorAppConfig(type)
+ };
+};
+
+export const createEditorAppConfig = (type: EditorAppType) => {
+ return {
+ $type: type,
+ languageId: 'typescript',
+ code: '',
+ useDiffEditor: false,
};
};