diff --git a/package-lock.json b/package-lock.json index 0a8ee8a..a234737 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2617,7 +2617,8 @@ "node_modules/monaco-editor": { "version": "0.36.1", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.36.1.tgz", - "integrity": "sha512-/CaclMHKQ3A6rnzBzOADfwdSJ25BFoFT0Emxsc4zYVyav5SkK9iA6lEtIeuN/oRYbwPgviJT+t3l+sjFa28jYg==" + "integrity": "sha512-/CaclMHKQ3A6rnzBzOADfwdSJ25BFoFT0Emxsc4zYVyav5SkK9iA6lEtIeuN/oRYbwPgviJT+t3l+sjFa28jYg==", + "peer": true }, "node_modules/monaco-editor-workers": { "resolved": "packages/monaco-editor-workers", @@ -4153,7 +4154,6 @@ "http-server": "~14.1.1", "langium": "~1.1.0", "langium-statemachine-dsl": "~1.1.0", - "monaco-editor": "0.36.1", "monaco-editor-workers": "0.36.0", "monaco-editor-wrapper": "2.0.0-next.1", "react": "~18.2.0", @@ -4269,23 +4269,14 @@ "license": "MIT", "dependencies": { "@types/css-font-loading-module": "~0.0.8", - "monaco-editor": "0.36.1", "monaco-languageclient": "5.0.1", "normalize-url": "~8.0.0", - "vscode": "npm:@codingame/monaco-vscode-api@~1.76.6", "vscode-ws-jsonrpc": "3.0.0" }, "devDependencies": { - "@types/glob-to-regexp": "~0.4.1", - "monaco-editor-workers": "0.36.0" + "@types/glob-to-regexp": "~0.4.1" } }, - "packages/monaco-editor-wrapper/node_modules/monaco-editor-workers": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/monaco-editor-workers/-/monaco-editor-workers-0.36.0.tgz", - "integrity": "sha512-byrccv+VN5MC9aAjLd4wGis1cPVYtaxvBRjlqupiv8BrNehuPqRlc+T3j1A6Ow62j5AAHxnzHtWkIwPvDDmYIg==", - "dev": true - }, "packages/monaco-editor-wrapper/node_modules/vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", diff --git a/packages/examples/package.json b/packages/examples/package.json index 5ae91c2..2348372 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -6,7 +6,6 @@ "http-server": "~14.1.1", "langium": "~1.1.0", "langium-statemachine-dsl": "~1.1.0", - "monaco-editor": "0.36.1", "monaco-editor-wrapper": "2.0.0-next.1", "@typefox/monaco-editor-react": "1.0.0-next.8", "monaco-editor-workers": "0.36.0", diff --git a/packages/examples/src/langium/langiumWrapperConfig.ts b/packages/examples/src/langium/langiumWrapperConfig.ts index f2b4ea6..4339b83 100644 --- a/packages/examples/src/langium/langiumWrapperConfig.ts +++ b/packages/examples/src/langium/langiumWrapperConfig.ts @@ -1,6 +1,6 @@ -import { GlobalConfig } from 'monaco-editor-wrapper'; +import { UserConfig } from 'monaco-editor-wrapper'; -export const createLangiumGlobalConfig = async (): Promise => { +export const createLangiumGlobalConfig = async (htmlElement: HTMLElement): Promise => { const exampleStatemachineUrl = new URL('./src/langium/example.statemachine', window.location.href).href; const responseStatemachine = await fetch(exampleStatemachineUrl); const code = await responseStatemachine.text(); @@ -16,6 +16,7 @@ export const createLangiumGlobalConfig = async (): Promise => { console.log(`Langium worker URL: ${workerUrl}`); return { + htmlElement: htmlElement, wrapperConfig: { useVscodeConfig: true, monacoVscodeApiConfig: { diff --git a/packages/examples/src/langium/reactLangium.tsx b/packages/examples/src/langium/reactLangium.tsx index 7e59ed3..9d00284 100644 --- a/packages/examples/src/langium/reactLangium.tsx +++ b/packages/examples/src/langium/reactLangium.tsx @@ -7,9 +7,9 @@ import { MonacoEditorReactComp } from '@typefox/monaco-editor-react'; import { createLangiumGlobalConfig } from './langiumWrapperConfig.js'; const startEditor = async () => { - const langiumGlobalConfig = await createLangiumGlobalConfig(); + const langiumGlobalConfig = await createLangiumGlobalConfig(document.getElementById('root')!); const comp = { alert('Editor was already started!'); return; } - const langiumGlobalConfig = await createLangiumGlobalConfig(); - wrapper.init(langiumGlobalConfig); - - wrapper.startEditor(document.getElementById('monaco-editor-root') as HTMLElement) + const langiumGlobalConfig = await createLangiumGlobalConfig(document.getElementById('monaco-editor-root') as HTMLElement); + wrapper + .init(langiumGlobalConfig) + .startEditor() .then((s: unknown) => { console.log(s); diff --git a/packages/examples/src/reactTs.tsx b/packages/examples/src/reactTs.tsx index b23969e..a0b1cd7 100644 --- a/packages/examples/src/reactTs.tsx +++ b/packages/examples/src/reactTs.tsx @@ -4,9 +4,10 @@ buildWorkerDefinition('../../../../node_modules/monaco-editor-workers/dist/worke import React from 'react'; import ReactDOM from 'react-dom/client'; import { MonacoEditorReactComp } from '@typefox/monaco-editor-react/allLanguages'; -import { GlobalConfig } from 'monaco-editor-wrapper'; +import { UserConfig } from 'monaco-editor-wrapper'; -const globalConfig: GlobalConfig = { +const userConfig: UserConfig = { + htmlElement: document.getElementById('root')!, wrapperConfig: { useVscodeConfig: false, monacoEditorConfig: { @@ -26,13 +27,18 @@ const globalConfig: GlobalConfig = { } }; +const onTextChanged = (text: string, isDirty: boolean) => { + console.log(`Dirty? ${isDirty} Content: ${text}`); +}; + const comp = ; const root = ReactDOM.createRoot(document.getElementById('root')!); diff --git a/packages/examples/src/wrapperAdvanced.ts b/packages/examples/src/wrapperAdvanced.ts index 0c12a56..fa74956 100644 --- a/packages/examples/src/wrapperAdvanced.ts +++ b/packages/examples/src/wrapperAdvanced.ts @@ -12,6 +12,7 @@ const startWrapper42 = () => { wrapperConfig: { useVscodeConfig: false }, + htmlElement: document.getElementById('monaco-editor-root-42') as HTMLElement, languageClientConfig: { enabled: true, useWebSocket: true, @@ -27,24 +28,25 @@ const startWrapper42 = () => { useDiffEditor: true, theme: 'vs-light', automaticLayout: true, + codeOriginal: `This line is equal. +This number is different 2002 +Misspeelled! +Same again.`, code: `This line is equal. This number is different 2022 Misspelled! -Same again.`, - codeModified: `This line is equal. -This number is different 2002 -Misspeelled! Same again.` } }); - wrapper42.startEditor(document.getElementById('monaco-editor-root-42') as HTMLElement) + wrapper42.startEditor() .catch((e: Error) => console.error(e)); }; const startWrapper43 = () => { wrapper43.init({ id: '43', + htmlElement: document.getElementById('monaco-editor-root-43') as HTMLElement, wrapperConfig: { useVscodeConfig: false }, @@ -56,21 +58,22 @@ const startWrapper43 = () => { useDiffEditor: true, theme: 'vs-light', automaticLayout: true, - code: 'This line is equal.\nThis number is different 3022.\nMisspelled!Same again.', - codeModified: 'This line is equal.\nThis number is different 3002.\nMisspelled!Same again.', + codeOriginal: 'This line is equal.\nThis number is different 3022.\nMisspelled!Same again.', + code: 'This line is equal.\nThis number is different 3002.\nMisspelled!Same again.', diffEditorOptions: { lineNumbers: 'off' } } }); - wrapper43.startEditor(document.getElementById('monaco-editor-root-43') as HTMLElement) + wrapper43.startEditor() .catch((e: Error) => console.error(e)); }; const startWrapper44 = () => { wrapper44.init({ id: '44', + htmlElement: document.getElementById('monaco-editor-root-44') as HTMLElement, wrapperConfig: { useVscodeConfig: false }, @@ -93,7 +96,7 @@ const startWrapper44 = () => { } }); - wrapper44.startEditor(document.getElementById('monaco-editor-root-44') as HTMLElement) + wrapper44.startEditor() .catch((e: Error) => console.error(e)); }; @@ -105,31 +108,33 @@ const sleepOne = (milliseconds: number) => { setTimeout(() => { alert(`Updating editors after ${milliseconds}ms`); - const config42 = wrapper42.getRuntimeConfig(); + // TODO: Update model can only work on same editor + const config42 = wrapper42.getUserConfig(); config42.editorConfig.languageId = 'javascript'; config42.editorConfig.useDiffEditor = false; config42.editorConfig.code = `function logMe() { + console.log('Hello swap editors!'); };`; - wrapper42.startEditor(document.getElementById('monaco-editor-root-42') as HTMLElement) + wrapper42.startEditor() .catch((e: Error) => console.error(e)); - const config43 = wrapper43.getRuntimeConfig(); - config43.editorConfig.languageId = 'javascript'; - config43.editorConfig.code = 'text 1234'; - config43.editorConfig.codeModified = 'text 5678'; - wrapper43.startEditor(document.getElementById('monaco-editor-root-43') as HTMLElement) - .catch((e: Error) => console.error(e)); + wrapper43.updateModel({ + useDiffEditor: true, + languageId: 'javascript', + code: 'text 5678', + codeOriginal: 'text 1234' + }); - const config44 = wrapper44.getRuntimeConfig(); + const config44 = wrapper44.getUserConfig(); config44.editorConfig.languageId = 'text/plain'; config44.editorConfig.useDiffEditor = true; - config44.editorConfig.code = 'oh la la la!'; - config44.editorConfig.codeModified = 'oh lo lo lo!'; + config44.editorConfig.codeOriginal = 'oh la la la!'; + config44.editorConfig.code = 'oh lo lo lo!'; // This affects all editors globally and is only effective // if it is not in contrast to one configured later config44.editorConfig.theme = 'vs-light'; - wrapper44.startEditor(document.getElementById('monaco-editor-root-44') as HTMLElement) + wrapper44.startEditor() .catch((e: Error) => console.error(e)); }, milliseconds); }; @@ -140,10 +145,10 @@ const sleepTwo = (milliseconds: number) => { setTimeout(() => { alert(`Updating last editor after ${milliseconds}ms`); - const config44 = wrapper44.getRuntimeConfig(); + const config44 = wrapper44.getUserConfig(); config44.editorConfig.useDiffEditor = false; config44.editorConfig.theme = 'vs-dark'; - wrapper44.startEditor(document.getElementById('monaco-editor-root-44') as HTMLElement) + wrapper44.startEditor() .catch((e: Error) => console.error(e)); }, milliseconds); }; diff --git a/packages/examples/src/wrapperTs.ts b/packages/examples/src/wrapperTs.ts index 39ecdbd..e0261fe 100644 --- a/packages/examples/src/wrapperTs.ts +++ b/packages/examples/src/wrapperTs.ts @@ -39,6 +39,7 @@ const monacoEditorConfig: editor.IStandaloneEditorConstructionOptions = { const wrapper = new MonacoEditorLanguageClientWrapper(); wrapper.init({ + htmlElement: document.getElementById('monaco-editor-root') as HTMLElement, wrapperConfig: { useVscodeConfig: false }, @@ -47,9 +48,9 @@ wrapper.init({ }, editorConfig: { languageId: languageId, - code: codeMain, + code: codeOrg, useDiffEditor: false, - codeModified: codeOrg, + codeOriginal: codeMain, editorOptions: monacoEditorConfig, diffEditorOptions: monacoEditorConfig, theme: 'vs-dark', @@ -65,7 +66,7 @@ function startEditor() { configureCodeEditors(); toggleSwapDiffButton(true); - wrapper.startEditor(document.getElementById('monaco-editor-root') as HTMLElement) + wrapper.startEditor() .then((s: unknown) => { console.log(s); logEditorInfo(wrapper); @@ -78,10 +79,10 @@ function startEditor() { } function configureCodeEditors() { - const runtimeConfig = wrapper.getRuntimeConfig(); + const runtimeConfig = wrapper.getUserConfig(); if (runtimeConfig.editorConfig.useDiffEditor) { - runtimeConfig.editorConfig.code = codeOrg; - runtimeConfig.editorConfig.codeModified = codeMain; + runtimeConfig.editorConfig.code = codeMain; + runtimeConfig.editorConfig.codeOriginal = codeOrg; } else { runtimeConfig.editorConfig.code = codeMain; } @@ -89,20 +90,20 @@ function configureCodeEditors() { function saveMainCode(saveFromDiff: boolean, saveFromMain: boolean) { if (saveFromDiff) { - codeMain = wrapper.getDiffCode()!; + codeMain = wrapper.getModel(true)!.getValue(); } if (saveFromMain) { - codeMain = wrapper.getMainCode()!; + codeMain = wrapper.getModel()!.getValue(); } } function swapEditors() { - const runtimeConfig = wrapper.getRuntimeConfig(); + const runtimeConfig = wrapper.getUserConfig(); runtimeConfig.editorConfig.useDiffEditor = !runtimeConfig.editorConfig.useDiffEditor; saveMainCode(!runtimeConfig.editorConfig.useDiffEditor, false); configureCodeEditors(); - wrapper.startEditor(document.getElementById('monaco-editor-root') as HTMLElement) + wrapper.startEditor() .then((s: string) => { console.log(s); logEditorInfo(wrapper); @@ -113,7 +114,7 @@ function swapEditors() { async function disposeEditor() { wrapper.reportStatus(); toggleSwapDiffButton(false); - const useDiffEditor = wrapper.getRuntimeConfig().editorConfig.useDiffEditor; + const useDiffEditor = wrapper.getUserConfig().editorConfig.useDiffEditor; saveMainCode(useDiffEditor, !useDiffEditor); await wrapper.dispose() .then(() => { @@ -131,8 +132,10 @@ function toggleSwapDiffButton(enabled: boolean) { function logEditorInfo(client: MonacoEditorLanguageClientWrapper) { console.log(`# of configured languages: ${languages.getLanguages().length}`); - console.log(`Main code: ${client.getMainCode()}`); - console.log(`Modified code: ${client.getDiffCode()}`); + console.log(`Main code: ${client.getModel(true)!.getValue()}`); + if (wrapper.getUserConfig().editorConfig.useDiffEditor) { + console.log(`Modified code: ${client.getModel()!.getValue()}`); + } } document.querySelector('#button-start')?.addEventListener('click', startEditor); diff --git a/packages/examples/src/wrapperWs.ts b/packages/examples/src/wrapperWs.ts index 9bd5c54..da9a522 100644 --- a/packages/examples/src/wrapperWs.ts +++ b/packages/examples/src/wrapperWs.ts @@ -26,6 +26,7 @@ const monacoEditorConfig = { }, }; wrapper.init({ + htmlElement: document.getElementById('monaco-editor-root') as HTMLElement, wrapperConfig: { useVscodeConfig: false, monacoEditorConfig: { @@ -37,12 +38,11 @@ wrapper.init({ } } }, - editorConfig: { languageId: languageId, code: codeMain, useDiffEditor: false, - codeModified: codeOrg, + codeOriginal: codeOrg, editorOptions: monacoEditorConfig, diffEditorOptions: monacoEditorConfig, theme: 'vs-dark', @@ -68,7 +68,7 @@ function startEditor() { configureCodeEditors(); toggleSwapDiffButton(true); - wrapper.startEditor(document.getElementById('monaco-editor-root') as HTMLElement) + wrapper.startEditor() .then((s: unknown) => { console.log(s); logEditorInfo(wrapper); @@ -81,10 +81,10 @@ function startEditor() { } function configureCodeEditors() { - const runtimeConfig = wrapper.getRuntimeConfig(); + const runtimeConfig = wrapper.getUserConfig(); if (runtimeConfig.editorConfig.useDiffEditor) { - runtimeConfig.editorConfig.code = codeOrg; - runtimeConfig.editorConfig.codeModified = codeMain; + runtimeConfig.editorConfig.code = codeMain; + runtimeConfig.editorConfig.codeOriginal = codeOrg; } else { runtimeConfig.editorConfig.code = codeMain; } @@ -92,20 +92,20 @@ function configureCodeEditors() { function saveMainCode(saveFromDiff: boolean, saveFromMain: boolean) { if (saveFromDiff) { - codeMain = wrapper.getDiffCode()!; + codeMain = wrapper.getModel(true)!.getValue(); } if (saveFromMain) { - codeMain = wrapper.getMainCode()!; + codeMain = wrapper.getModel()!.getValue(); } } function swapEditors() { - const runtimeConfig = wrapper.getRuntimeConfig(); + const runtimeConfig = wrapper.getUserConfig(); runtimeConfig.editorConfig.useDiffEditor = !runtimeConfig.editorConfig.useDiffEditor; saveMainCode(!runtimeConfig.editorConfig.useDiffEditor, false); configureCodeEditors(); - wrapper.startEditor(document.getElementById('monaco-editor-root') as HTMLElement) + wrapper.startEditor() .then((s: string) => { console.log(s); logEditorInfo(wrapper); @@ -116,7 +116,7 @@ function swapEditors() { async function disposeEditor() { wrapper.reportStatus(); toggleSwapDiffButton(false); - const useDiffEditor = wrapper.getRuntimeConfig().editorConfig.useDiffEditor; + const useDiffEditor = wrapper.getUserConfig().editorConfig.useDiffEditor; saveMainCode(useDiffEditor, !useDiffEditor); await wrapper.dispose() .then(() => { @@ -134,8 +134,10 @@ function toggleSwapDiffButton(enabled: boolean) { function logEditorInfo(client: MonacoEditorLanguageClientWrapper) { console.log(`# of configured languages: ${monaco.languages.getLanguages().length}`); - console.log(`Main code: ${client.getMainCode()}`); - console.log(`Modified code: ${client.getDiffCode()}`); + console.log(`Main code: ${client.getModel(true)!.getValue()}`); + if (wrapper.getUserConfig().editorConfig.useDiffEditor) { + console.log(`Modified code: ${client.getModel()!.getValue()}`); + } } document.querySelector('#button-start')?.addEventListener('click', startEditor); diff --git a/packages/monaco-editor-react/src/index.tsx b/packages/monaco-editor-react/src/index.tsx index 0f3137a..130f230 100644 --- a/packages/monaco-editor-react/src/index.tsx +++ b/packages/monaco-editor-react/src/index.tsx @@ -1,37 +1,23 @@ import React, { CSSProperties } from 'react'; -import { MonacoEditorLanguageClientWrapper, GlobalConfig } from 'monaco-editor-wrapper'; +import { MonacoEditorLanguageClientWrapper, UserConfig } from 'monaco-editor-wrapper'; import 'monaco-editor/esm/vs/editor/edcore.main.js'; -import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'; +import { IDisposable } from 'monaco-editor/esm/vs/editor/editor.api.js'; import * as vscode from 'vscode'; -// import { getMonacoCss } from 'monaco-editor-wrapper/monaco-css'; export type MonacoEditorProps = { style?: CSSProperties; className?: string; - /* - languageId: string; - text: string; - webworkerUri?: string; - syntax?: monaco.languages.IMonarchLanguage; - languageExtensionConfig?: MonacoLanguageExtensionConfig; - theme?: string, - workerName?: string, - workerType?: WorkerType, - rawMonacoEditorOptions?: monaco.editor.IEditorOptions & monaco.editor.IGlobalEditorOptions, -*/ - globalConfig: GlobalConfig, + userConfig: UserConfig, onTextChanged?: (text: string, isDirty: boolean) => void; onLoading?: () => void; onLoad?: () => void; } export class MonacoEditorReactComp extends React.Component { - private wrapper: MonacoEditorLanguageClientWrapper | null = null; + private wrapper: MonacoEditorLanguageClientWrapper = new MonacoEditorLanguageClientWrapper(); private containerElement?: HTMLDivElement; - - private _subscription: monaco.IDisposable | null = null; - + private _subscription: IDisposable | null = null; private isStarting?: Promise; constructor(props: MonacoEditorProps) { @@ -40,29 +26,29 @@ export class MonacoEditorReactComp extends React.Component { } override componentDidMount() { - this.destroyMonaco().then(() => this.initMonaco()); + this.destroyMonaco().then(() => { + this.initMonaco(); + }); } override componentDidUpdate(prevProps: MonacoEditorProps) { - const { className, globalConfig } = this.props; - + const { className, userConfig } = this.props; const { wrapper } = this; - /* - const innerEditor: monaco.editor.IStandaloneCodeEditor = - // eslint-disable-next-line dot-notation - wrapper!['editor']; - */ + if (prevProps.className !== className && this.containerElement) { this.containerElement.className = className ?? ''; } - const prevUrl = prevProps.globalConfig.languageClientConfig.workerConfigOptions?.url; - const url = globalConfig.languageClientConfig.workerConfigOptions?.url; + const prevUrl = prevProps.userConfig.languageClientConfig.workerConfigOptions?.url; + const url = userConfig.languageClientConfig.workerConfigOptions?.url; if (prevUrl !== url) { this.destroyMonaco().then(() => this.initMonaco()); } else { - // TODO: we need to update the wrapper config - wrapper!.updateWrapperConfig(); - wrapper!.updateEditorConfig(); + if (wrapper !== null) { + // TODO: we need to update the wrapper config + wrapper.updateWrapperConfig(); + wrapper.updateEditorConfig(); + } + /* wrapper!.startEditor(); wrapper!.getRuntimeConfig().editorConfig.languageId = languageId; @@ -96,8 +82,6 @@ export class MonacoEditorReactComp extends React.Component { // Sometimes the language client throws an error during disposal // This should not prevent us from continue working } - // eslint-disable-next-line dot-notation - this.wrapper['languageClient'] = undefined; } if (this._subscription) { this._subscription.dispose(); @@ -107,18 +91,7 @@ export class MonacoEditorReactComp extends React.Component { private async initMonaco() { const { className, - globalConfig, - /* - text, - syntax, - languageId, - webworkerUri, - rawMonacoEditorOptions, - workerName, - workerType, - theme, - languageExtensionConfig, -*/ + userConfig, onTextChanged, onLoading, onLoad, @@ -126,82 +99,34 @@ export class MonacoEditorReactComp extends React.Component { if (this.containerElement) { this.containerElement.className = className ?? ''; - this.wrapper = new MonacoEditorLanguageClientWrapper(); - this.wrapper.init(globalConfig); - /* - { - id: '42', - wrapperConfig: { - useVscodeConfig: false, - }, - content: { - languageId: languageId, - code: text, - useDiffEditor: false - }, - theme: theme ?? 'vs-dark' - }); -*/ - const runtimeConfig = this.wrapper.getRuntimeConfig(); - /* - monacoEditorWrapper.setMonarchTokensProvider(syntax); - if (languageExtensionConfig) { - monacoEditorWrapper.setLanguageExtensionConfig(languageExtensionConfig); - } + this.wrapper.init(userConfig); - if (rawMonacoEditorOptions) { - this.wrapper.setMonacoEditorOptions(rawMonacoEditorOptions); - } - else { - this.wrapper.setMonacoEditorOptions({}); - } - - if (webworkerUri) { - const workerURL = new URL(webworkerUri, window.origin); - const lsWorker = new Worker(workerURL.href, { - type: workerType ?? 'classic', - name: workerName ?? 'LanguageServerWorker', - }); - this.wrapper.setWorker(lsWorker); - } -*/ - this.isStarting = this.wrapper.startEditor(this.containerElement); + this.isStarting = this.wrapper.startEditor(); await this.isStarting; onLoading && onLoading(); onLoad && this.isStarting.then(() => onLoad()); if (onTextChanged) { - // eslint-disable-next-line dot-notation - const innerEditor: monaco.editor.IStandaloneCodeEditor = this.wrapper['editor']; - const model = innerEditor.getModel(); + const model = this.wrapper.getModel(); if (model) { - this._subscription = model.onDidChangeContent(() => { + const verifyModelContent = () => { const modelText = model.getValue(); - onTextChanged(modelText, modelText !== runtimeConfig.editorConfig.code); + onTextChanged(modelText, modelText !== userConfig.editorConfig.code); + }; + + this._subscription = model.onDidChangeContent(() => { + verifyModelContent(); }); - const currentValue = model.getValue(); - if (currentValue !== runtimeConfig.editorConfig.code) { - onTextChanged(currentValue, true); - } + // do it initially + verifyModelContent(); } } } } updateLayout(): void { - this.wrapper!.updateLayout(); - } - - getText(): string { - try { - // eslint-disable-next-line dot-notation - const innerEditor: monaco.editor.IStandaloneCodeEditor = this.wrapper!['editor']; - const model = innerEditor.getModel(); - return model?.getValue() ?? ''; - } catch { - return ''; - } + this.wrapper.updateLayout(); } getEditorWrapper() { @@ -228,13 +153,3 @@ export class MonacoEditorReactComp extends React.Component { ); } } - -export function addMonacoStyles(idOfStyleElement: string) { - const style = document.createElement('style'); - style.id = idOfStyleElement; - // style.innerHTML = getMonacoCss(); - style.innerHTML = ''; - document.head.appendChild(style); -} - -export { monaco, vscode }; diff --git a/packages/monaco-editor-react/src/indexAllLanguages.tsx b/packages/monaco-editor-react/src/indexAllLanguages.tsx index 3741b0a..78ea63a 100644 --- a/packages/monaco-editor-react/src/indexAllLanguages.tsx +++ b/packages/monaco-editor-react/src/indexAllLanguages.tsx @@ -4,9 +4,6 @@ export type { export { MonacoEditorReactComp, - addMonacoStyles, - monaco, - vscode } from './index.js'; import 'monaco-editor-wrapper/languagesOnly'; diff --git a/packages/monaco-editor-wrapper/package.json b/packages/monaco-editor-wrapper/package.json index e4b5c59..0f86888 100644 --- a/packages/monaco-editor-wrapper/package.json +++ b/packages/monaco-editor-wrapper/package.json @@ -95,15 +95,12 @@ }, "dependencies": { "@types/css-font-loading-module": "~0.0.8", - "monaco-editor": "0.36.1", "monaco-languageclient": "5.0.1", "vscode-ws-jsonrpc": "3.0.0", - "normalize-url": "~8.0.0", - "vscode": "npm:@codingame/monaco-vscode-api@~1.76.6" + "normalize-url": "~8.0.0" }, "devDependencies": { - "@types/glob-to-regexp": "~0.4.1", - "monaco-editor-workers": "0.36.0" + "@types/glob-to-regexp": "~0.4.1" }, "repository": { "type": "git", diff --git a/packages/monaco-editor-wrapper/src/index.ts b/packages/monaco-editor-wrapper/src/index.ts index deab012..a966b2d 100644 --- a/packages/monaco-editor-wrapper/src/index.ts +++ b/packages/monaco-editor-wrapper/src/index.ts @@ -18,7 +18,7 @@ import type { EditorConfig, WebSocketConfigOptions, WorkerConfigOptions, - GlobalConfig, + UserConfig, RuntimeConfig } from './wrapper.js'; @@ -32,7 +32,7 @@ export type { MonacoVscodeApiActivtion, WebSocketConfigOptions, WorkerConfigOptions, - GlobalConfig, + UserConfig, RuntimeConfig }; diff --git a/packages/monaco-editor-wrapper/src/indexAllLanguages.ts b/packages/monaco-editor-wrapper/src/indexAllLanguages.ts index 3617055..754e1de 100644 --- a/packages/monaco-editor-wrapper/src/indexAllLanguages.ts +++ b/packages/monaco-editor-wrapper/src/indexAllLanguages.ts @@ -4,7 +4,7 @@ export type { MonacoVscodeApiActivtion, WebSocketConfigOptions, WorkerConfigOptions, - GlobalConfig, + UserConfig, RuntimeConfig } from './index.js'; diff --git a/packages/monaco-editor-wrapper/src/monacoVscodeApiWrapper.ts b/packages/monaco-editor-wrapper/src/monacoVscodeApiWrapper.ts index 9bfd521..e4a1c0a 100644 --- a/packages/monaco-editor-wrapper/src/monacoVscodeApiWrapper.ts +++ b/packages/monaco-editor-wrapper/src/monacoVscodeApiWrapper.ts @@ -13,7 +13,7 @@ import getThemeServiceOverride from 'vscode/service-override/theme'; import getAudioCueServiceOverride from 'vscode/service-override/audioCue'; // import getDebugServiceOverride from 'vscode/service-override/debug'; import { createConfiguredEditor, createConfiguredDiffEditor } from 'vscode/monaco'; -import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js'; +import { editor } from 'monaco-editor/esm/vs/editor/editor.api.js'; import { loadAllDefaultThemes } from './helpers/themeLocalHelper.js'; export type MonacoVscodeApiActivtion = { @@ -127,11 +127,11 @@ export class MonacoVscodeApiWrapper { } } - createEditor(container: HTMLElement, options?: monaco.editor.IStandaloneEditorConstructionOptions) { + createEditor(container: HTMLElement, options?: editor.IStandaloneEditorConstructionOptions) { return createConfiguredEditor(container!, options); } - createDiffEditor(container: HTMLElement, options?: monaco.editor.IStandaloneDiffEditorConstructionOptions) { + createDiffEditor(container: HTMLElement, options?: editor.IStandaloneDiffEditorConstructionOptions) { return createConfiguredDiffEditor(container!, options); } } diff --git a/packages/monaco-editor-wrapper/src/wrapper.ts b/packages/monaco-editor-wrapper/src/wrapper.ts index 4596def..66ed651 100644 --- a/packages/monaco-editor-wrapper/src/wrapper.ts +++ b/packages/monaco-editor-wrapper/src/wrapper.ts @@ -1,7 +1,6 @@ // support all editor features -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import { editor, Uri } from 'monaco-editor/esm/vs/editor/edcore.main.js'; +import 'monaco-editor/esm/vs/editor/edcore.main.js'; +import { editor, Uri } from 'monaco-editor/esm/vs/editor/editor.api.js'; import { MonacoLanguageClient, MonacoServices } from 'monaco-languageclient'; import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'; @@ -31,7 +30,7 @@ export type EditorConfig = { useDiffEditor: boolean; theme: string; automaticLayout: boolean; - codeModified?: string; + codeOriginal?: string; editorOptions?: editor.IStandaloneEditorConstructionOptions; diffEditorOptions?: editor.IStandaloneDiffEditorConstructionOptions; } @@ -45,8 +44,9 @@ export type LanguageClientConfig = { initializationOptions?: any; } -export type GlobalConfig = { +export type UserConfig = { id?: string; + htmlElement: HTMLElement; wrapperConfig: { useVscodeConfig: boolean; monacoVscodeApiConfig?: MonacoVscodeApiWrapperConfig; @@ -58,6 +58,7 @@ export type GlobalConfig = { export type RuntimeConfig = { id: string; + htmlElement: HTMLElement; wrapperConfig: { useVscodeConfig: boolean; monacoVscodeApiConfig?: MonacoVscodeApiWrapperConfig; @@ -77,57 +78,65 @@ export class MonacoEditorLanguageClientWrapper { private monacoEditorWrapper = new MonacoEditorWrapper(); private monacoVscodeApiWrapper = new MonacoVscodeApiWrapper(); + + private userConfig: UserConfig; private runtimeConfig: RuntimeConfig; - init(config: GlobalConfig) { - if (config.editorConfig.useDiffEditor) { - if (!config.editorConfig.codeModified) { + init(userConfig: UserConfig): MonacoEditorLanguageClientWrapper { + this.userConfig = userConfig; + if (userConfig.editorConfig.useDiffEditor) { + if (!userConfig.editorConfig.codeOriginal) { throw new Error('Use diff editor was used without a valid config.'); } } // It is ensured that the runtime configuration always contains proper values this.runtimeConfig = { - id: config.id ?? Math.floor(Math.random() * 101).toString(), + id: userConfig.id ?? Math.floor(Math.random() * 101).toString(), + htmlElement: userConfig.htmlElement, wrapperConfig: { - useVscodeConfig: config.wrapperConfig.useVscodeConfig, + useVscodeConfig: userConfig.wrapperConfig.useVscodeConfig, }, editorConfig: { - languageId: config.editorConfig.languageId, - code: config.editorConfig.code ?? '', - useDiffEditor: config.editorConfig.useDiffEditor === true, - theme: config.editorConfig.theme ?? 'vs-light', - automaticLayout: config.editorConfig.automaticLayout === true, - editorOptions: config.editorConfig.editorOptions ?? {}, - diffEditorOptions: config.editorConfig.diffEditorOptions ?? {} + languageId: userConfig.editorConfig.languageId, + code: userConfig.editorConfig.code ?? '', + useDiffEditor: userConfig.editorConfig.useDiffEditor === true, + theme: userConfig.editorConfig.theme ?? 'vs-light', + automaticLayout: userConfig.editorConfig.automaticLayout === true, + editorOptions: userConfig.editorConfig.editorOptions ?? { + automaticLayout: userConfig.editorConfig.automaticLayout === true + }, + diffEditorOptions: userConfig.editorConfig.diffEditorOptions ?? { + automaticLayout: userConfig.editorConfig.automaticLayout === true + } }, languageClientConfig: { - enabled: config.languageClientConfig.enabled, - useWebSocket: config.languageClientConfig.useWebSocket === true, + enabled: userConfig.languageClientConfig.enabled, + useWebSocket: userConfig.languageClientConfig.useWebSocket === true, } }; - if (config.editorConfig.codeModified) { - this.runtimeConfig.editorConfig.codeModified = config.editorConfig.codeModified; + if (userConfig.editorConfig.codeOriginal) { + this.runtimeConfig.editorConfig.codeOriginal = userConfig.editorConfig.codeOriginal; } - if (config.editorConfig.editorOptions) { - this.runtimeConfig.editorConfig.editorOptions = config.editorConfig.editorOptions; + if (userConfig.editorConfig.editorOptions) { + this.runtimeConfig.editorConfig.editorOptions = userConfig.editorConfig.editorOptions; } - if (config.editorConfig.diffEditorOptions) { - this.runtimeConfig.editorConfig.diffEditorOptions = config.editorConfig.diffEditorOptions; + if (userConfig.editorConfig.diffEditorOptions) { + this.runtimeConfig.editorConfig.diffEditorOptions = userConfig.editorConfig.diffEditorOptions; } - if (config.languageClientConfig.enabled) { - if (config.languageClientConfig.initializationOptions) { - this.runtimeConfig.languageClientConfig.initializationOptions = config.languageClientConfig.initializationOptions; + if (userConfig.languageClientConfig.enabled) { + if (userConfig.languageClientConfig.initializationOptions) { + this.runtimeConfig.languageClientConfig.initializationOptions = userConfig.languageClientConfig.initializationOptions; } - if (config.languageClientConfig.useWebSocket) { - if (config.languageClientConfig.webSocketConfigOptions) { - this.runtimeConfig.languageClientConfig.webSocketConfigOptions = config.languageClientConfig.webSocketConfigOptions; + if (userConfig.languageClientConfig.useWebSocket) { + if (userConfig.languageClientConfig.webSocketConfigOptions) { + this.runtimeConfig.languageClientConfig.webSocketConfigOptions = userConfig.languageClientConfig.webSocketConfigOptions; } else { throw new Error('webSocketConfigOptions were not provided. Aborting...'); } } else { - if (config.languageClientConfig.workerConfigOptions) { - this.runtimeConfig.languageClientConfig.workerConfigOptions = config.languageClientConfig.workerConfigOptions; + if (userConfig.languageClientConfig.workerConfigOptions) { + this.runtimeConfig.languageClientConfig.workerConfigOptions = userConfig.languageClientConfig.workerConfigOptions; } else { throw new Error('workerConfigOptions were not provided. Aborting...'); } @@ -135,24 +144,26 @@ export class MonacoEditorLanguageClientWrapper { } if (this.runtimeConfig.wrapperConfig.useVscodeConfig) { - if (config.wrapperConfig.monacoVscodeApiConfig) { - this.runtimeConfig.wrapperConfig.monacoVscodeApiConfig = config.wrapperConfig.monacoVscodeApiConfig; - this.monacoVscodeApiWrapper.init(config.wrapperConfig.monacoVscodeApiConfig); + if (userConfig.wrapperConfig.monacoVscodeApiConfig) { + this.runtimeConfig.wrapperConfig.monacoVscodeApiConfig = userConfig.wrapperConfig.monacoVscodeApiConfig; + this.monacoVscodeApiWrapper.init(this.runtimeConfig.wrapperConfig.monacoVscodeApiConfig); } else { throw new Error('monacoVscodeApiConfig was not provided. Aborting...'); } } else { - if (config.wrapperConfig.monacoEditorConfig) { - this.runtimeConfig.wrapperConfig.monacoEditorConfig = config.wrapperConfig.monacoEditorConfig; + if (userConfig.wrapperConfig.monacoEditorConfig) { + this.runtimeConfig.wrapperConfig.monacoEditorConfig = userConfig.wrapperConfig.monacoEditorConfig; } else { this.runtimeConfig.wrapperConfig.monacoEditorConfig = {}; } this.monacoEditorWrapper.init(this.runtimeConfig.editorConfig, this.runtimeConfig.wrapperConfig.monacoEditorConfig); } + + return this; } - getRuntimeConfig() { - return this.runtimeConfig; + getUserConfig() { + return this.userConfig; } getMonacoEditorWrapper() { @@ -175,24 +186,30 @@ export class MonacoEditorLanguageClientWrapper { return this.languageClient; } - getMainCode(): string | undefined { - if (this.editor) { - return this.editor?.getValue(); + getModel(original?: boolean): editor.ITextModel | undefined { + if (this.runtimeConfig.editorConfig.useDiffEditor) { + const model = this.diffEditor?.getModel(); + return (original === true) ? model?.original : model?.modified; } else { - return this.diffEditor?.getOriginalEditor().getValue(); + return this.editor?.getModel() ?? undefined; } } - getDiffCode(): string | undefined { - return this.diffEditor?.getModifiedEditor().getValue(); - } - - /** - * This methods updates the theme. If the given provide theme is not available this will not work. - * @param theme the theme name - */ - updateTheme(theme: string) { - editor.setTheme(theme); + updateModel(modelUpdate: { + languageId: string; + code: string; + useDiffEditor: boolean; + codeOriginal?: string; + }) { + this.runtimeConfig.editorConfig.languageId = modelUpdate.languageId; + this.runtimeConfig.editorConfig.code = modelUpdate.code; + this.runtimeConfig.editorConfig.useDiffEditor = modelUpdate.useDiffEditor; + if (this.runtimeConfig.editorConfig.useDiffEditor) { + this.runtimeConfig.editorConfig.codeOriginal = modelUpdate.codeOriginal; + this.updateDiffEditorModel(); + } else { + this.updateEditorModel(); + } } isStarted(): boolean { @@ -208,11 +225,8 @@ export class MonacoEditorLanguageClientWrapper { return true; } - startEditor(container?: HTMLElement): Promise { + startEditor(): Promise { console.log(`Starting monaco-editor (${this.runtimeConfig.id})`); - if (!container) { - return Promise.reject(new Error('No HTMLElement was provided.')); - } // dispose old instances (try both, no need for swap) this.disposeEditor(); @@ -220,9 +234,9 @@ export class MonacoEditorLanguageClientWrapper { this.updateWrapperConfig(); if (this.runtimeConfig.editorConfig.useDiffEditor) { - this.createDiffEditor(container); + this.createDiffEditor(this.runtimeConfig.htmlElement); } else { - this.createEditor(container); + this.createEditor(this.runtimeConfig.htmlElement); } const lcc = this.runtimeConfig.languageClientConfig; @@ -294,7 +308,7 @@ export class MonacoEditorLanguageClientWrapper { return status; } - private async disposeLanguageClient(): Promise { + public async disposeLanguageClient(): Promise { if (this.languageClient && this.languageClient.isRunning()) { return await this.languageClient.dispose() .then(() => { @@ -313,37 +327,45 @@ export class MonacoEditorLanguageClientWrapper { } private createEditor(container: HTMLElement): void { - const runtimeConfig = this.runtimeConfig; - const languageId = runtimeConfig.editorConfig.languageId; - const mainUri = Uri.parse(`inmemory:///model${runtimeConfig.id}.${languageId}`); - const model = editor.getModel(mainUri); - if (model === null || !runtimeConfig.editorConfig.editorOptions.model) { - runtimeConfig.editorConfig.editorOptions.model = editor.createModel(runtimeConfig.editorConfig.code, languageId, mainUri); - } - runtimeConfig.editorConfig.editorOptions.automaticLayout = runtimeConfig.editorConfig.automaticLayout; + this.updateEditorModel(); - if (runtimeConfig.wrapperConfig.useVscodeConfig) { - this.editor = this.monacoVscodeApiWrapper.createEditor(container!, runtimeConfig.editorConfig.editorOptions); + if (this.runtimeConfig.wrapperConfig.useVscodeConfig) { + this.editor = this.monacoVscodeApiWrapper.createEditor(container!, this.runtimeConfig.editorConfig.editorOptions); } else { - this.editor = this.monacoEditorWrapper.createEditor(container, runtimeConfig.editorConfig.editorOptions); + this.editor = this.monacoEditorWrapper.createEditor(container, this.runtimeConfig.editorConfig.editorOptions); } } - private createDiffEditor(container: HTMLElement) { - const runtimeConfig = this.runtimeConfig; - runtimeConfig.editorConfig.diffEditorOptions.automaticLayout = runtimeConfig.editorConfig.automaticLayout; + private updateEditorModel() { + const languageId = this.runtimeConfig.editorConfig.languageId; + const id = this.runtimeConfig.id; + const mainUri = Uri.parse(`inmemory:///model${id}.${languageId}`); + let model = editor.getModel(mainUri); + if (model === null) { + model = editor.createModel(this.runtimeConfig.editorConfig.code, languageId, mainUri); + } + this.runtimeConfig.editorConfig.editorOptions!.model = model; - if (runtimeConfig.wrapperConfig.useVscodeConfig) { - this.diffEditor = this.monacoVscodeApiWrapper.createDiffEditor(container, runtimeConfig.editorConfig.diffEditorOptions); + this.editor?.setModel(model); + } + + private createDiffEditor(container: HTMLElement) { + if (this.runtimeConfig.wrapperConfig.useVscodeConfig) { + this.diffEditor = this.monacoVscodeApiWrapper.createDiffEditor(container, this.runtimeConfig.editorConfig.diffEditorOptions); } else { - this.diffEditor = this.monacoEditorWrapper.createDiffEditor(container, runtimeConfig.editorConfig.diffEditorOptions); + this.diffEditor = this.monacoEditorWrapper.createDiffEditor(container, this.runtimeConfig.editorConfig.diffEditorOptions); } - const languageId = runtimeConfig.editorConfig.languageId; - const mainCode = runtimeConfig.editorConfig.code; - const modifiedCode = runtimeConfig.editorConfig.codeModified; - const mainUri = Uri.parse(`inmemory:///model${runtimeConfig.id}.${languageId}`); - const modifiedUri = Uri.parse(`inmemory:///modelDiff${runtimeConfig.id}.${languageId}`); + this.updateDiffEditorModel(); + } + + private updateDiffEditorModel() { + const languageId = this.runtimeConfig.editorConfig.languageId; + const mainCode = this.runtimeConfig.editorConfig.codeOriginal!; + const modifiedCode = this.runtimeConfig.editorConfig.code; + const id = this.runtimeConfig.id; + const mainUri = Uri.parse(`inmemory:///model${id}.${languageId}`); + const modifiedUri = Uri.parse(`inmemory:///modelDiff${id}.${languageId}`); let originalModel = editor.getModel(mainUri); if (originalModel === null) { @@ -355,7 +377,7 @@ export class MonacoEditorLanguageClientWrapper { modifiedModel = editor.createModel(modifiedCode!, languageId, modifiedUri); } - this.diffEditor.setModel({ + this.diffEditor?.setModel({ original: originalModel, modified: modifiedModel }); diff --git a/tsconfig.json b/tsconfig.json index 47865eb..aaab98a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -40,6 +40,7 @@ }, "include": [ "**/src/**/*.ts", + "**/src/**/*.js", "**/test/**/*.ts", "**/src/**/*.tsx", "**/test/**/*.tsx",