33* Licensed under the MIT License. See LICENSE in the package root for license information.
44* ------------------------------------------------------------------------------------------ */
55
6- import { Deferred } from 'monaco-languageclient/common ' ;
6+ import * as monaco from '@codingame/ monaco-vscode-editor-api ' ;
77import { EditorApp , type EditorAppConfig , type TextContents } from 'monaco-languageclient/editorApp' ;
88import { type LanguageClientConfig , LanguageClientManager } from 'monaco-languageclient/lcwrapper' ;
99import { getEnhancedMonacoEnvironment , type MonacoVscodeApiConfig , MonacoVscodeApiWrapper } from 'monaco-languageclient/vscodeApiWrapper' ;
@@ -22,6 +22,7 @@ export type MonacoEditorProps = {
2222 onEditorStartDone ?: ( editorApp ?: EditorApp ) => void ;
2323 onLanguageClientsStartDone ?: ( lcsManager ?: LanguageClientManager ) => void ;
2424 onTextChanged ?: ( textChanges : TextContents ) => void ;
25+ onConfigProcessed ?: ( editorApp ?: EditorApp ) => void ;
2526 onError ?: ( error : Error ) => void ;
2627 onDisposeEditor ?: ( ) => void ;
2728 onDisposeLanguageClient ?: ( ) => void ;
@@ -37,45 +38,47 @@ const haveEditorService = () => {
3738} ;
3839
3940const runQueue : Array < { id : string , func : ( ) => Promise < void > } > = [ ] ;
40- let deferred : Deferred | undefined = new Deferred ( ) ;
41+ // let deferred: Deferred = new Deferred();
42+ let lock = true ;
4143let intervalId : number | unknown | undefined = undefined ;
4244
4345const addQueue = ( id : string , func : ( ) => Promise < void > ) => {
44- debugLogging ( '=======================' ) ;
45- debugLogging ( `Adding to queue: ${ id } ` ) ;
46- debugLogging ( `QUEUE SIZE before: ${ runQueue . length } ` ) ;
46+ debugLogging ( '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' ) ;
47+ debugLogging ( `Adding to queue: ${ id } : QUEUE SIZE before: ${ runQueue . length } ` ) ;
4748 runQueue . push ( { id, func} ) ;
4849
4950 kickQueue ( ) ;
5051} ;
5152
5253const executeQueue = async ( ) => {
53- deferred = new Deferred ( ) ;
54- while ( runQueue . length > 0 ) {
55- const queueObj = runQueue . shift ( ) ;
56- if ( queueObj !== undefined ) {
57- debugLogging ( '=======================' ) ;
58- debugLogging ( `QUEUE ${ queueObj . id } SIZE before: ${ runQueue . length } ` ) ;
59- debugLogging ( `QUEUE ${ queueObj . id } start` , true ) ;
60- await queueObj . func ( ) ;
61- debugLogging ( `QUEUE ${ queueObj . id } SIZE after: ${ runQueue . length } ` ) ;
62- debugLogging ( `QUEUE ${ queueObj . id } end` ) ;
54+ // while (runQueue.length > 0) {
55+ console . log ( `Queue size: ${ runQueue . length } ` ) ;
56+
57+ if ( runQueue . length > 0 ) {
58+ lock = true ;
59+ while ( runQueue . length > 0 ) {
60+ // deferred = new Deferred();
61+ const lengthBefore = runQueue . length ;
62+ const queueObj = runQueue . shift ( ) ;
63+ debugLogging ( '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<' ) ;
64+ debugLogging ( `QUEUE ${ queueObj ?. id } start: SIZE before: ${ lengthBefore } ` , true ) ;
65+ await queueObj ?. func ( ) ;
66+ debugLogging ( `QUEUE ${ queueObj ?. id } end: SIZE after: ${ runQueue . length } ` ) ;
67+ // deferred.resolve();
6368 }
69+ lock = false ;
6470 }
65- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
66- deferred ?. resolve ( ) ;
67- deferred = undefined ;
68- stopQueue ( ) ;
6971} ;
7072
7173const kickQueue = ( ) => {
7274 if ( intervalId === undefined && runQueue . length > 0 ) {
7375 intervalId = setInterval ( async ( ) => {
74- if ( deferred !== undefined ) {
75- await deferred . promise ;
76- }
7776 debugLogging ( 'Checking queue...' ) ;
78- executeQueue ( ) ;
77+ if ( ! lock ) {
78+ // await deferred.promise;
79+ executeQueue ( ) ;
80+ stopQueue ( ) ;
81+ }
7982 } , 50 ) ;
8083 }
8184} ;
@@ -108,19 +111,21 @@ export const MonacoEditorReactComp: React.FC<MonacoEditorProps> = (props) => {
108111 onEditorStartDone,
109112 onLanguageClientsStartDone,
110113 onTextChanged,
114+ onConfigProcessed,
111115 onError,
112116 onDisposeEditor,
113117 onDisposeLanguageClient,
114118 modifiedTextValue,
115119 originalTextValue
116120 } = props ;
117121
118- const currentEditorConfig = useRef < EditorAppConfig | undefined > ( undefined ) ;
119122 const editorAppRef = useRef < EditorApp > ( undefined ) ;
120123 const containerRef = useRef < HTMLDivElement > ( null ) ;
121124 const onTextChangedRef = useRef ( onTextChanged ) ;
122125 const modifiedCode = useRef < string > ( modifiedTextValue ) ;
123126 const originalCode = useRef < string > ( originalTextValue ) ;
127+ const launchingRef = useRef < boolean > ( false ) ;
128+ const editorAppConfigRef = useRef < EditorAppConfig > ( undefined ) ;
124129
125130 const performErrorHandling = ( error : Error ) => {
126131 if ( onError ) {
@@ -174,7 +179,8 @@ export const MonacoEditorReactComp: React.FC<MonacoEditorProps> = (props) => {
174179 onVscodeApiInitDone ?.( apiWrapper ) ;
175180 debugLogging ( 'GLOBAL INIT DONE' , true ) ;
176181
177- deferred ?. resolve ( ) ;
182+ // deferred?.resolve();
183+ lock = false ;
178184 } catch ( error ) {
179185 performErrorHandling ( error as Error ) ;
180186 }
@@ -183,69 +189,83 @@ export const MonacoEditorReactComp: React.FC<MonacoEditorProps> = (props) => {
183189 }
184190 } ;
185191
186- useEffect ( ( ) => {
187- // fast-fail
188- if ( editorAppConfig === undefined ) return ;
192+ const editorInitFunc = async ( ) => {
193+ try {
194+ debugLogging ( 'INIT' , true ) ;
195+
196+ // it is possible to run without an editorApp, for example when using the ViewsService
197+ if ( haveEditorService ( ) ) {
198+ if ( editorAppRef . current === undefined && ! launchingRef . current ) {
199+ launchingRef . current = true ;
200+ debugLogging ( 'INIT: Creating editor' , true ) ;
201+
202+ editorAppRef . current = new EditorApp ( editorAppConfigRef . current ) ;
203+ if ( editorAppRef . current . isStarting ( ) === true || editorAppRef . current . isDisposing ( ) === true ) {
204+ await Promise . all ( [
205+ editorAppRef . current . getStartingAwait ( ) ,
206+ editorAppRef . current . getDisposingAwait ( )
207+ ] ) ;
208+ }
189209
190- // always try to perform global init. Reason: we cannot ensure order
191- performGlobalInit ( ) ;
210+ editorAppRef . current . registerOnTextChangedCallback ( ( textChanges ) => {
211+ if ( textChanges . modified !== undefined ) {
212+ modifiedCode . current = textChanges . modified ;
213+ }
214+ if ( textChanges . original !== undefined ) {
215+ originalCode . current = textChanges . original ;
216+ }
217+ if ( onTextChangedRef . current !== undefined ) {
218+ onTextChangedRef . current ( textChanges ) ;
219+ }
220+ } ) ;
221+ await editorAppRef . current . start ( containerRef . current ! ) ;
192222
193- // re-create editor if config changed
194- const recreateEditor = editorAppRef . current === undefined || currentEditorConfig . current === undefined ||
195- JSON . stringify ( editorAppConfig ) !== JSON . stringify ( currentEditorConfig . current ) ;
196- if ( recreateEditor ) {
197- const editorInitFunc = async ( ) => {
198- try {
199- debugLogging ( 'INIT' , true ) ;
223+ onEditorStartDone ?.( editorAppRef . current ) ;
224+ launchingRef . current = false ;
225+ }
226+ }
200227
201- // it is possible to run without an editorApp, for example when using the ViewsService
202- if ( haveEditorService ( ) ) {
203- debugLogging ( 'INIT: Creating editor' , true ) ;
228+ debugLogging ( 'INIT DONE' , true ) ;
229+ } catch ( error ) {
230+ performErrorHandling ( error as Error ) ;
231+ }
232+ } ;
204233
205- await handleEditorDispose ( ) ;
234+ const configProcessedFunc = ( ) => {
235+ if ( ! launchingRef . current ) {
236+ if ( editorAppConfigRef . current ?. codeResources !== undefined && editorAppRef . current ) {
237+ editorAppRef . current . updateCodeResources ( editorAppConfigRef . current . codeResources ) ;
238+ }
239+ if ( editorAppConfigRef . current ?. editorOptions !== undefined && editorAppRef . current ) {
240+ if ( ! editorAppRef . current . isDiffEditor ( ) ) {
241+ editorAppRef . current . getEditor ( ) ?. updateOptions ( editorAppConfigRef . current . editorOptions as monaco . editor . IEditorOptions ) ;
242+ }
243+ }
244+ if ( editorAppConfigRef . current ?. diffEditorOptions !== undefined && editorAppRef . current ) {
245+ if ( editorAppRef . current . isDiffEditor ( ) ) {
246+ editorAppRef . current . getDiffEditor ( ) ?. updateOptions ( editorAppConfigRef . current . diffEditorOptions as monaco . editor . IDiffEditorOptions ) ;
247+ }
248+ }
249+ }
250+ onConfigProcessed ?.( editorAppRef . current ) ;
251+ debugLogging ( 'Config processed' ) ;
252+ } ;
206253
207- currentEditorConfig . current = editorAppConfig ;
208- editorAppRef . current = new EditorApp ( editorAppConfig ) ;
209- if ( editorAppRef . current . isStarting ( ) === true || editorAppRef . current . isDisposing ( ) === true ) {
210- await Promise . all ( [
211- editorAppRef . current . getStartingAwait ( ) ,
212- editorAppRef . current . getDisposingAwait ( )
213- ] ) ;
214- }
254+ useEffect ( ( ) => {
255+ // fast-fail
256+ if ( editorAppConfig === undefined ) return ;
215257
216- editorAppRef . current . registerOnTextChangedCallback ( ( textChanges ) => {
217- if ( textChanges . modified !== undefined ) {
218- modifiedCode . current = textChanges . modified ;
219- }
220- if ( textChanges . original !== undefined ) {
221- originalCode . current = textChanges . original ;
222- }
223- if ( onTextChangedRef . current !== undefined ) {
224- onTextChangedRef . current ( textChanges ) ;
225- }
226- } ) ;
227- await editorAppRef . current . start ( containerRef . current ! ) ;
258+ // always try to perform global init. Reason: we cannot ensure order
259+ performGlobalInit ( ) ;
228260
229- onEditorStartDone ?.( editorAppRef . current ) ;
230- }
261+ editorAppConfigRef . current = editorAppConfig ;
231262
232- debugLogging ( 'INIT DONE' , true ) ;
233- } catch ( error ) {
234- performErrorHandling ( error as Error ) ;
235- }
236- } ;
237- addQueue ( 'editorInit' , editorInitFunc ) ;
263+ addQueue ( 'editorInit' , editorInitFunc ) ;
264+ if ( editorAppRef . current !== undefined && ! launchingRef . current ) {
265+ configProcessedFunc ( ) ;
238266 }
239267 } , [ editorAppConfig ] ) ;
240268
241- const handleEditorDispose = async ( ) => {
242- if ( editorAppRef . current !== undefined ) {
243- await editorAppRef . current . dispose ( ) ;
244- editorAppRef . current = undefined ;
245- onDisposeEditor ?.( ) ;
246- }
247- } ;
248-
249269 useEffect ( ( ) => {
250270 // fast-fail
251271 if ( languageClientConfig === undefined ) return ;
@@ -282,7 +302,11 @@ export const MonacoEditorReactComp: React.FC<MonacoEditorProps> = (props) => {
282302 // dispose editor if used
283303 debugLogging ( 'DISPOSE' , true ) ;
284304
285- await handleEditorDispose ( ) ;
305+ if ( editorAppRef . current !== undefined ) {
306+ await editorAppRef . current . dispose ( ) ;
307+ editorAppRef . current = undefined ;
308+ onDisposeEditor ?.( ) ;
309+ }
286310
287311 debugLogging ( 'DISPOSE DONE' , true ) ;
288312 } ;
0 commit comments