monaco-languageclient 10.0.0-next.0 → 10.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +20 -3
  2. package/README.md +98 -34
  3. package/lib/common/utils.d.ts +1 -1
  4. package/lib/common/utils.d.ts.map +1 -1
  5. package/lib/common/utils.js +1 -1
  6. package/lib/common/utils.js.map +1 -1
  7. package/lib/editorApp/config.d.ts +0 -2
  8. package/lib/editorApp/config.d.ts.map +1 -1
  9. package/lib/editorApp/config.js +1 -2
  10. package/lib/editorApp/config.js.map +1 -1
  11. package/lib/editorApp/editorApp.d.ts +4 -11
  12. package/lib/editorApp/editorApp.d.ts.map +1 -1
  13. package/lib/editorApp/editorApp.js +73 -88
  14. package/lib/editorApp/editorApp.js.map +1 -1
  15. package/lib/fs/definitions.d.ts +2 -2
  16. package/lib/fs/definitions.d.ts.map +1 -1
  17. package/lib/vscode/apiWrapper.d.ts +21 -6
  18. package/lib/vscode/apiWrapper.d.ts.map +1 -1
  19. package/lib/vscode/apiWrapper.js +67 -39
  20. package/lib/vscode/apiWrapper.js.map +1 -1
  21. package/lib/vscode/config.d.ts +8 -6
  22. package/lib/vscode/config.d.ts.map +1 -1
  23. package/lib/vscode/config.js +1 -1
  24. package/lib/vscode/utils.d.ts.map +1 -1
  25. package/lib/vscode/utils.js +4 -5
  26. package/lib/vscode/utils.js.map +1 -1
  27. package/lib/worker/index.js +1 -1
  28. package/lib/wrapper/lcconfig.d.ts +3 -3
  29. package/lib/wrapper/lcconfig.d.ts.map +1 -1
  30. package/lib/wrapper/lcconfig.js +1 -1
  31. package/lib/wrapper/lcmanager.d.ts +2 -1
  32. package/lib/wrapper/lcmanager.d.ts.map +1 -1
  33. package/lib/wrapper/lcmanager.js +21 -17
  34. package/lib/wrapper/lcmanager.js.map +1 -1
  35. package/lib/wrapper/lcwrapper.d.ts +1 -1
  36. package/lib/wrapper/lcwrapper.d.ts.map +1 -1
  37. package/lib/wrapper/lcwrapper.js +10 -9
  38. package/lib/wrapper/lcwrapper.js.map +1 -1
  39. package/package.json +41 -40
  40. package/src/common/utils.ts +1 -1
  41. package/src/editorApp/config.ts +1 -3
  42. package/src/editorApp/editorApp.ts +81 -96
  43. package/src/fs/definitions.ts +2 -2
  44. package/src/vscode/apiWrapper.ts +84 -44
  45. package/src/vscode/config.ts +13 -8
  46. package/src/vscode/utils.ts +4 -5
  47. package/src/worker/index.ts +1 -1
  48. package/src/wrapper/lcconfig.ts +5 -5
  49. package/src/wrapper/lcmanager.ts +23 -18
  50. package/src/wrapper/lcwrapper.ts +10 -9
@@ -8,12 +8,13 @@ import { createModelReference, type ITextFileEditorModel } from '@codingame/mona
8
8
  import * as monaco from '@codingame/monaco-vscode-editor-api';
9
9
  import type { IReference } from '@codingame/monaco-vscode-editor-service-override';
10
10
  import { ConsoleLogger, type Logger } from 'monaco-languageclient/common';
11
- import { getEnhancedMonacoEnvironment, type OverallConfigType } from 'monaco-languageclient/vscodeApiWrapper';
11
+ import { getEnhancedMonacoEnvironment } from 'monaco-languageclient/vscodeApiWrapper';
12
12
  import * as vscode from 'vscode';
13
- import { ModelRefs, type CallbackDisposeable, type CodeContent, type CodeResources, type DisposableModelRefs, type EditorAppConfig, type TextContents, type TextModels } from './config.js';
13
+ import type { CallbackDisposeable, CodeContent, CodeResources, DisposableModelRefs, EditorAppConfig, TextContents, TextModels } from './config.js';
14
+ import { ModelRefs } from './config.js';
14
15
 
15
16
  /**
16
- * This is the base class for both Monaco Ediotor Apps:
17
+ * This is the base class for both Monaco Editor Apps:
17
18
  * - EditorAppClassic
18
19
  * - EditorAppExtended
19
20
  *
@@ -21,7 +22,6 @@ import { ModelRefs, type CallbackDisposeable, type CodeContent, type CodeResourc
21
22
  */
22
23
  export class EditorApp {
23
24
 
24
- private $type: OverallConfigType;
25
25
  private id: string;
26
26
  private config: EditorAppConfig;
27
27
 
@@ -33,19 +33,16 @@ export class EditorApp {
33
33
  private modelRefs: ModelRefs = new ModelRefs();
34
34
 
35
35
  private onTextChanged?: (textChanges: TextContents) => void;
36
- private textChangedDiposeables: CallbackDisposeable = {};
36
+ private textChangedDisposables: CallbackDisposeable = {};
37
37
  private modelDisposables: DisposableModelRefs = {};
38
38
 
39
39
  private modelRefDisposeTimeout = -1;
40
40
 
41
41
  private startingAwait?: Promise<void>;
42
- private startingResolve: (value: void | PromiseLike<void>) => void;
43
42
 
44
43
  private disposingAwait?: Promise<void>;
45
- private disposingResolve: (value: void | PromiseLike<void>) => void;
46
44
 
47
45
  constructor(userAppConfig?: EditorAppConfig) {
48
- this.$type = userAppConfig?.$type ?? 'extended';
49
46
  this.id = userAppConfig?.id ?? Math.floor(Math.random() * 1000001).toString();
50
47
  if ((userAppConfig?.useDiffEditor ?? false) && !userAppConfig?.codeResources?.original) {
51
48
  throw new Error(`Use diff editor was used without a valid config. code: ${userAppConfig?.codeResources?.modified} codeOriginal: ${userAppConfig?.codeResources?.original}`);
@@ -105,17 +102,6 @@ export class EditorApp {
105
102
  this.modelRefDisposeTimeout = modelRefDisposeTimeout;
106
103
  }
107
104
 
108
- private markStarting() {
109
- this.startingAwait = new Promise<void>((resolve) => {
110
- this.startingResolve = resolve;
111
- });
112
- }
113
-
114
- private markStarted() {
115
- this.startingResolve();
116
- this.startingAwait = undefined;
117
- }
118
-
119
105
  isStarting() {
120
106
  return this.startingAwait !== undefined;
121
107
  }
@@ -135,44 +121,71 @@ export class EditorApp {
135
121
  if (this.isStarting()) {
136
122
  await this.getStartingAwait();
137
123
  }
138
- this.markStarting();
139
124
 
140
- if (!this.isDisposed()) {
141
- throw new Error('You called start without properly disposing the EditorApp.');
142
- }
125
+ let startingResolve: (value: void | PromiseLike<void>) => void = () => { };
126
+ this.startingAwait = new Promise<void>((resolve) => {
127
+ startingResolve = resolve;
128
+ });
129
+
130
+ try {
131
+ const envEnhanced = getEnhancedMonacoEnvironment();
132
+ const viewServiceType = envEnhanced.viewServiceType;
143
133
 
144
- const languageDef = this.config.languageDef;
145
- if (languageDef) {
146
- if (this.$type === 'extended') {
147
- throw new Error('Language definition is not supported for extended editor apps where textmate is used.');
134
+ // check general error case first
135
+ if (!(envEnhanced.vscodeApiInitialised ?? false)) {
136
+ return Promise.reject('monaco-vscode-api was not initialized. Aborting.');
148
137
  }
149
- // register own language first
150
- monaco.languages.register(languageDef.languageExtensionConfig);
151
-
152
- const languageRegistered = monaco.languages.getLanguages().filter(x => x.id === languageDef.languageExtensionConfig.id);
153
- if (languageRegistered.length === 0) {
154
- // this is only meaningful for languages supported by monaco out of the box
155
- monaco.languages.register({
156
- id: languageDef.languageExtensionConfig.id
157
- });
138
+ if (viewServiceType !== 'EditorService' && viewServiceType !== undefined) {
139
+ return Promise.reject('No EditorService configured. monaco-editor will not be started.');
140
+ }
141
+ if (!this.isDisposed()) {
142
+ return Promise.reject('Start was called without properly disposing the EditorApp first.');
158
143
  }
159
144
 
160
- // apply monarch definitions
161
- if (languageDef.monarchLanguage) {
162
- monaco.languages.setMonarchTokensProvider(languageDef.languageExtensionConfig.id, languageDef.monarchLanguage);
145
+ const languageDef = this.config.languageDef;
146
+ if (languageDef) {
147
+ // register own language first
148
+ monaco.languages.register(languageDef.languageExtensionConfig);
149
+
150
+ const languageRegistered = monaco.languages.getLanguages().filter(x => x.id === languageDef.languageExtensionConfig.id);
151
+ if (languageRegistered.length === 0) {
152
+ // this is only meaningful for languages supported by monaco out of the box
153
+ monaco.languages.register({
154
+ id: languageDef.languageExtensionConfig.id
155
+ });
156
+ }
157
+
158
+ // apply monarch definitions
159
+ if (languageDef.monarchLanguage) {
160
+ monaco.languages.setMonarchTokensProvider(languageDef.languageExtensionConfig.id, languageDef.monarchLanguage);
161
+ }
162
+
163
+ if (languageDef.theme) {
164
+ monaco.editor.defineTheme(languageDef.theme.name, languageDef.theme.data);
165
+ monaco.editor.setTheme(languageDef.theme.name);
166
+ }
163
167
  }
164
168
 
165
- if (languageDef.theme) {
166
- monaco.editor.defineTheme(languageDef.theme.name, languageDef.theme.data);
167
- monaco.editor.setTheme(languageDef.theme.name);
169
+ if (this.config.editorOptions?.['semanticHighlighting.enabled'] !== undefined) {
170
+ StandaloneServices.get(IConfigurationService).updateValue('editor.semanticHighlighting.enabled',
171
+ this.config.editorOptions['semanticHighlighting.enabled'], ConfigurationTarget.USER);
168
172
  }
169
- }
170
173
 
171
- if (this.config.editorOptions?.['semanticHighlighting.enabled'] !== undefined) {
172
- StandaloneServices.get(IConfigurationService).updateValue('editor.semanticHighlighting.enabled',
173
- this.config.editorOptions['semanticHighlighting.enabled'], ConfigurationTarget.USER);
174
+ await this.createEditors(htmlContainer);
175
+
176
+ // everything is fine at this point
177
+ startingResolve();
178
+ this.logger.info('EditorApp start completed successfully.');
179
+ } catch (e) {
180
+ // in case of further errors (after general ones above)
181
+ // take the error and build a new rejection to complete the promise
182
+ return Promise.reject(e);
183
+ } finally {
184
+ this.startingAwait = undefined;
174
185
  }
186
+ }
175
187
 
188
+ async createEditors(htmlContainer: HTMLElement): Promise<void> {
176
189
  // ensure proper default resources are initialized, uris have to be unique
177
190
  const modified = {
178
191
  text: this.config.codeResources?.modified?.text ?? '',
@@ -190,30 +203,10 @@ export class EditorApp {
190
203
  this.modelRefs.original = await this.buildModelReference(original, this.logger);
191
204
  }
192
205
 
193
- try {
194
- const envEnhanced = getEnhancedMonacoEnvironment();
195
- const viewServiceType = envEnhanced.viewServiceType;
196
- if (viewServiceType === 'EditorService' || viewServiceType === undefined) {
197
- this.logger.info(`Starting monaco-editor (${this.id})`);
198
- await this.createEditors(htmlContainer!);
199
- } else {
200
- this.logger.info('No EditorService configured. monaco-editor will not be started.');
201
- }
202
-
203
- this.logger.info('EditorApp start completed successfully.');
204
- // eslint-disable-next-line no-useless-catch
205
- } catch (e) {
206
- throw e;
207
- } finally {
208
- // in case of rejection, mark as started, otherwise the promise will never resolve
209
- this.markStarted();
210
- }
211
- }
212
-
213
- async createEditors(htmlContainer: HTMLElement): Promise<void> {
206
+ this.logger.info(`Starting monaco-editor (${this.id})`);
214
207
  if (this.isDiffEditor()) {
215
208
  this.diffEditor = monaco.editor.createDiffEditor(htmlContainer, this.config.diffEditorOptions);
216
- const modified = this.modelRefs.modified?.object.textEditorModel ?? undefined;
209
+ const modified = this.modelRefs.modified.object.textEditorModel ?? undefined;
217
210
  const original = this.modelRefs.original?.object.textEditorModel ?? undefined;
218
211
  if (modified !== undefined && original !== undefined) {
219
212
  const model = {
@@ -225,7 +218,7 @@ export class EditorApp {
225
218
  }
226
219
  } else {
227
220
  const model = {
228
- modified: this.modelRefs.modified?.object.textEditorModel
221
+ modified: this.modelRefs.modified.object.textEditorModel
229
222
  };
230
223
  this.editor = monaco.editor.create(htmlContainer, {
231
224
  ...this.config.editorOptions,
@@ -318,8 +311,8 @@ export class EditorApp {
318
311
  if (this.onTextChanged !== undefined) {
319
312
  let changed = false;
320
313
  if (textModels.modified !== undefined && textModels.modified !== null) {
321
- const old = this.textChangedDiposeables.modified;
322
- this.textChangedDiposeables.modified = textModels.modified.onDidChangeContent(() => {
314
+ const old = this.textChangedDisposables.modified;
315
+ this.textChangedDisposables.modified = textModels.modified.onDidChangeContent(() => {
323
316
  didModelContentChange(textModels, this.onTextChanged);
324
317
  });
325
318
  old?.dispose();
@@ -327,8 +320,8 @@ export class EditorApp {
327
320
  }
328
321
 
329
322
  if (textModels.original !== undefined && textModels.original !== null) {
330
- const old = this.textChangedDiposeables.original;
331
- this.textChangedDiposeables.original = textModels.original.onDidChangeContent(() => {
323
+ const old = this.textChangedDisposables.original;
324
+ this.textChangedDisposables.original = textModels.original.onDidChangeContent(() => {
332
325
  didModelContentChange(textModels, this.onTextChanged);
333
326
  });
334
327
  old?.dispose();
@@ -346,7 +339,10 @@ export class EditorApp {
346
339
  if (this.isDisposing()) {
347
340
  await this.getDisposingAwait();
348
341
  }
349
- this.markDisposing();
342
+ let disposingResolve: (value: void | PromiseLike<void>) => void = () => { };
343
+ this.disposingAwait = new Promise<void>((resolve) => {
344
+ disposingResolve = resolve;
345
+ });
350
346
 
351
347
  if (this.editor) {
352
348
  this.editor.dispose();
@@ -357,33 +353,22 @@ export class EditorApp {
357
353
  this.diffEditor = undefined;
358
354
  }
359
355
 
360
- this.textChangedDiposeables.modified?.dispose();
361
- this.textChangedDiposeables.original?.dispose();
362
- this.textChangedDiposeables.modified = undefined;
363
- this.textChangedDiposeables.original = undefined;
356
+ this.textChangedDisposables.modified?.dispose();
357
+ this.textChangedDisposables.original?.dispose();
358
+ this.textChangedDisposables.modified = undefined;
359
+ this.textChangedDisposables.original = undefined;
364
360
 
365
361
  await this.disposeModelRefs();
366
362
 
367
- this.markDisposed();
363
+ disposingResolve();
364
+ this.disposingAwait = undefined;
368
365
  }
369
366
 
370
367
  isDisposed(): boolean {
371
368
  return this.editor === undefined && this.diffEditor === undefined &&
372
- // this.textChangedDiposeables.modified === undefined && this.textChangedDiposeables.original === undefined &&
373
369
  this.modelDisposables.original === undefined && this.modelDisposables.modified === undefined;
374
370
  }
375
371
 
376
- private markDisposing() {
377
- this.disposingAwait = new Promise<void>((resolve) => {
378
- this.disposingResolve = resolve;
379
- });
380
- }
381
-
382
- private markDisposed() {
383
- this.disposingResolve();
384
- this.disposingAwait = undefined;
385
- }
386
-
387
372
  isDisposing() {
388
373
  return this.disposingAwait !== undefined;
389
374
  }
@@ -393,7 +378,7 @@ export class EditorApp {
393
378
  }
394
379
 
395
380
  async disposeModelRefs() {
396
- const diposeRefs = () => {
381
+ const disposeRefs = () => {
397
382
  if (this.logger.getLevel() === LogLevel.Debug) {
398
383
  const models = monaco.editor.getModels();
399
384
  this.logger.debug('Current model URIs:');
@@ -402,11 +387,11 @@ export class EditorApp {
402
387
  });
403
388
  }
404
389
 
405
- if (this.modelDisposables.modified !== undefined && !(this.modelDisposables.modified.object.isDisposed() === true)) {
390
+ if (this.modelDisposables.modified !== undefined && !this.modelDisposables.modified.object.isDisposed()) {
406
391
  this.modelDisposables.modified.dispose();
407
392
  this.modelDisposables.modified = undefined;
408
393
  }
409
- if (this.modelDisposables.original !== undefined && !(this.modelDisposables.original.object.isDisposed() === true)) {
394
+ if (this.modelDisposables.original !== undefined && !this.modelDisposables.original.object.isDisposed()) {
410
395
  this.modelDisposables.original.dispose();
411
396
  this.modelDisposables.original = undefined;
412
397
  }
@@ -423,11 +408,11 @@ export class EditorApp {
423
408
  if (this.modelRefDisposeTimeout > 0) {
424
409
  this.logger.debug('Using async dispose of model references');
425
410
  await new Promise<void>(resolve => setTimeout(() => {
426
- diposeRefs();
411
+ disposeRefs();
427
412
  resolve();
428
413
  }, this.modelRefDisposeTimeout));
429
414
  } else {
430
- diposeRefs();
415
+ disposeRefs();
431
416
  }
432
417
  }
433
418
 
@@ -13,12 +13,12 @@ export type FileReadResultStatus = 'success' | 'denied';
13
13
 
14
14
  export interface FileReadRequestResult {
15
15
  status: FileReadResultStatus
16
- content: string | ArrayBuffer
16
+ content: string | ArrayBuffer | ArrayBufferLike | BlobPart
17
17
  }
18
18
 
19
19
  export interface FileUpdate {
20
20
  resourceUri: string
21
- content: string | ArrayBuffer
21
+ content: string | ArrayBuffer | ArrayBufferLike | BlobPart
22
22
  }
23
23
 
24
24
  export type FileUpdateResultStatus = 'equal' | 'updated' | 'created' | 'denied';
@@ -1,5 +1,5 @@
1
1
  /* --------------------------------------------------------------------------------------------
2
- * Copyright (c) 2024 TypeFox and others.
2
+ * Copyright (c) 2025 TypeFox and others.
3
3
  * Licensed under the MIT License. See LICENSE in the package root for license information.
4
4
  * ------------------------------------------------------------------------------------------ */
5
5
 
@@ -7,20 +7,29 @@ import { initialize, LogLevel } from '@codingame/monaco-vscode-api';
7
7
  import { ExtensionHostKind, getExtensionManifests, registerExtension, type IExtensionManifest, type RegisterExtensionResult } from '@codingame/monaco-vscode-api/extensions';
8
8
  import { DisposableStore, setUnexpectedErrorHandler } from '@codingame/monaco-vscode-api/monaco';
9
9
  import getConfigurationServiceOverride, { initUserConfiguration } from '@codingame/monaco-vscode-configuration-service-override';
10
- import getLanguagesServiceOverride from '@codingame/monaco-vscode-languages-service-override';
10
+ import * as monaco from '@codingame/monaco-vscode-editor-api';
11
11
  import getLogServiceOverride from '@codingame/monaco-vscode-log-service-override';
12
12
  import getModelServiceOverride from '@codingame/monaco-vscode-model-service-override';
13
- import { ConsoleLogger, verifyUrlOrCreateDataUrl, type Logger } from 'monaco-languageclient/common';
13
+ import { ConsoleLogger, encodeStringOrUrlToDataUrl, type Logger } from 'monaco-languageclient/common';
14
14
  import { useWorkerFactory } from 'monaco-languageclient/workerFactory';
15
15
  import * as vscode from 'vscode';
16
16
  import 'vscode/localExtensionHost';
17
- import type { MonacoVscodeApiConfig } from './config.js';
17
+ import type { ExtensionConfig, MonacoVscodeApiConfig, ViewsConfig } from './config.js';
18
18
  import { configureExtHostWorker, getEnhancedMonacoEnvironment, mergeServices, reportServiceLoading, useOpenEditorStub } from './utils.js';
19
19
 
20
- export interface InitServicesInstructions {
20
+ export interface ViewsConfigRuntime extends ViewsConfig {
21
+ htmlContainer: HTMLElement;
22
+ }
23
+
24
+ export interface MonacoVscodeApiConfigRuntime extends MonacoVscodeApiConfig {
25
+ serviceOverrides: monaco.editor.IEditorOverrideServices;
26
+ logLevel: LogLevel | number;
27
+ viewsConfig: ViewsConfigRuntime;
28
+ }
29
+
30
+ export interface StartInstructions {
21
31
  caller?: string;
22
32
  performServiceConsistencyChecks?: boolean;
23
- htmlContainer?: HTMLElement | null;
24
33
  }
25
34
 
26
35
  export class MonacoVscodeApiWrapper {
@@ -28,11 +37,20 @@ export class MonacoVscodeApiWrapper {
28
37
  private logger: Logger = new ConsoleLogger();
29
38
  private extensionRegisterResults: Map<string, | RegisterExtensionResult> = new Map();
30
39
  private disposableStore: DisposableStore = new DisposableStore();
31
- private apiConfig: MonacoVscodeApiConfig;
40
+ private apiConfig: MonacoVscodeApiConfigRuntime;
32
41
 
33
42
  constructor(apiConfig: MonacoVscodeApiConfig) {
34
- this.apiConfig = apiConfig;
35
- this.apiConfig.logLevel = this.apiConfig.logLevel ?? LogLevel.Off;
43
+ const intermediate = {
44
+ ...apiConfig,
45
+ serviceOverrides: apiConfig.serviceOverrides ?? {},
46
+ logLevel: apiConfig.logLevel ?? LogLevel.Off,
47
+ };
48
+ if (intermediate.viewsConfig.htmlContainer === 'ReactPlaceholder') {
49
+ // this is temporary and must be overriden at start by react component with
50
+ // correct react dom element
51
+ intermediate.viewsConfig.htmlContainer = document.body;
52
+ }
53
+ this.apiConfig = intermediate as MonacoVscodeApiConfigRuntime;
36
54
  this.logger.setLevel(this.apiConfig.logLevel);
37
55
  }
38
56
 
@@ -48,6 +66,10 @@ export class MonacoVscodeApiWrapper {
48
66
  return this.apiConfig;
49
67
  }
50
68
 
69
+ getHtmlContainer() {
70
+ return this.apiConfig.viewsConfig.htmlContainer;
71
+ }
72
+
51
73
  protected configureMonacoWorkers() {
52
74
  if (typeof this.apiConfig.monacoWorkerFactory === 'function') {
53
75
  this.apiConfig.monacoWorkerFactory(this.logger);
@@ -62,7 +84,9 @@ export class MonacoVscodeApiWrapper {
62
84
  if (this.apiConfig.$type === 'extended') {
63
85
  const getTextmateServiceOverride = (await import('@codingame/monaco-vscode-textmate-service-override')).default;
64
86
  const getThemeServiceOverride = (await import('@codingame/monaco-vscode-theme-service-override')).default;
87
+ const getLanguagesServiceOverride = (await import('@codingame/monaco-vscode-languages-service-override')).default;
65
88
  mergeServices(this.apiConfig.serviceOverrides, {
89
+ ...getLanguagesServiceOverride(),
66
90
  ...getTextmateServiceOverride(),
67
91
  ...getThemeServiceOverride()
68
92
  });
@@ -75,19 +99,19 @@ export class MonacoVscodeApiWrapper {
75
99
  }
76
100
 
77
101
  protected async configureViewsServices() {
78
- const viewServiceType = this.apiConfig.viewsConfig?.viewServiceType ?? 'EditorService';
79
- if (this.apiConfig.$type === 'classic' && (viewServiceType === 'ViewsService' || viewServiceType === 'WorkspaceService')) {
80
- throw new Error(`View Service Type "${viewServiceType}" cannot be used with classic configuration.`);
102
+ const viewsConfigType = this.apiConfig.viewsConfig.$type;
103
+ if (this.apiConfig.$type === 'classic' && (viewsConfigType === 'ViewsService' || viewsConfigType === 'WorkspaceService')) {
104
+ throw new Error(`View Service Type "${viewsConfigType}" cannot be used with classic configuration.`);
81
105
  }
82
106
 
83
107
  const envEnhanced = getEnhancedMonacoEnvironment();
84
- if (this.apiConfig.viewsConfig?.viewServiceType === 'ViewsService') {
108
+ if (viewsConfigType === 'ViewsService') {
85
109
  const getViewsServiceOverride = (await import('@codingame/monaco-vscode-views-service-override')).default;
86
110
  mergeServices(this.apiConfig.serviceOverrides, {
87
111
  ...getViewsServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub)
88
112
  });
89
113
  envEnhanced.viewServiceType = 'ViewsService';
90
- } else if (this.apiConfig.viewsConfig?.viewServiceType === 'WorkspaceService') {
114
+ } else if (viewsConfigType === 'WorkspaceService') {
91
115
  const getWorkbenchServiceOverride = (await import('@codingame/monaco-vscode-workbench-service-override')).default;
92
116
  mergeServices(this.apiConfig.serviceOverrides, {
93
117
  ...getWorkbenchServiceOverride()
@@ -96,15 +120,15 @@ export class MonacoVscodeApiWrapper {
96
120
  } else {
97
121
  const getEditorServiceOverride = (await import('@codingame/monaco-vscode-editor-service-override')).default;
98
122
  mergeServices(this.apiConfig.serviceOverrides, {
99
- ...getEditorServiceOverride(this.apiConfig.viewsConfig?.openEditorFunc ?? useOpenEditorStub)
123
+ ...getEditorServiceOverride(this.apiConfig.viewsConfig.openEditorFunc ?? useOpenEditorStub)
100
124
  });
101
125
  envEnhanced.viewServiceType = 'EditorService';
102
126
  }
103
127
  }
104
128
 
105
129
  protected async applyViewsPostConfig() {
106
- this.apiConfig.viewsConfig?.htmlAugmentationInstructions?.(this.apiConfig.htmlContainer);
107
- await this.apiConfig.viewsConfig?.viewsInitFunc?.();
130
+ this.apiConfig.viewsConfig.htmlAugmentationInstructions?.(this.apiConfig.viewsConfig.htmlContainer);
131
+ await this.apiConfig.viewsConfig.viewsInitFunc?.();
108
132
  }
109
133
 
110
134
  /**
@@ -128,13 +152,13 @@ export class MonacoVscodeApiWrapper {
128
152
  }
129
153
 
130
154
  /**
131
- * set the log-level via the development settings
155
+ * Set the log-level via the development settings.
156
+ * VSCode developmentOptions are read-only. There are no functions exposed to set options directly.
157
+ * Therefore the Object properties need to be manipulated directly via Object.assign.
132
158
  */
133
159
  protected configureDevLogLevel() {
134
160
  const devLogLevel = this.apiConfig.workspaceConfig?.developmentOptions?.logLevel;
135
161
  if (devLogLevel === undefined) {
136
-
137
- // this needs to be done so complicated, because developmentOptions is read-only
138
162
  const devOptions: Record<string, unknown> = {
139
163
  ...this.apiConfig.workspaceConfig!.developmentOptions
140
164
  };
@@ -169,7 +193,6 @@ export class MonacoVscodeApiWrapper {
169
193
  protected async supplyRequiredServices() {
170
194
  return {
171
195
  ...getConfigurationServiceOverride(),
172
- ...getLanguagesServiceOverride(),
173
196
  ...getLogServiceOverride(),
174
197
  ...getModelServiceOverride()
175
198
  };
@@ -204,8 +227,9 @@ export class MonacoVscodeApiWrapper {
204
227
  * - languages
205
228
  * - log
206
229
  * - model
230
+ * - configuration services
207
231
  */
208
- protected async importAllServices(instructions?: InitServicesInstructions) {
232
+ protected async initAllServices(performServiceConsistencyChecks?: boolean) {
209
233
  const services = await this.supplyRequiredServices();
210
234
 
211
235
  mergeServices(services, this.apiConfig.serviceOverrides);
@@ -213,12 +237,12 @@ export class MonacoVscodeApiWrapper {
213
237
 
214
238
  reportServiceLoading(services, this.logger);
215
239
 
216
- if (instructions?.performServiceConsistencyChecks === true) {
240
+ if (performServiceConsistencyChecks ?? true) {
217
241
  this.checkServiceConsistency();
218
242
  }
219
243
 
220
- if (this.apiConfig.viewsConfig?.viewServiceType === 'ViewsService' || this.apiConfig.viewsConfig?.viewServiceType === 'WorkspaceService') {
221
- await initialize(services, this.apiConfig.htmlContainer, this.apiConfig.workspaceConfig, this.apiConfig.envOptions);
244
+ if (this.apiConfig.viewsConfig.$type === 'ViewsService' || this.apiConfig.viewsConfig.$type === 'WorkspaceService') {
245
+ await initialize(services, this.apiConfig.viewsConfig.htmlContainer, this.apiConfig.workspaceConfig, this.apiConfig.envOptions);
222
246
  } else {
223
247
  await initialize(services, undefined, this.apiConfig.workspaceConfig, this.apiConfig.envOptions);
224
248
  }
@@ -242,21 +266,29 @@ export class MonacoVscodeApiWrapper {
242
266
  });
243
267
  for (const extensionConfig of extensions ?? []) {
244
268
  if (!extensionIds.includes(`${extensionConfig.config.publisher}.${extensionConfig.config.name}`)) {
245
- const manifest = extensionConfig.config as IExtensionManifest;
246
- const extRegResult = registerExtension(manifest, ExtensionHostKind.LocalProcess);
247
- this.extensionRegisterResults.set(manifest.name, extRegResult);
248
- if (extensionConfig.filesOrContents && Object.hasOwn(extRegResult, 'registerFileUrl')) {
249
- for (const entry of extensionConfig.filesOrContents) {
250
- this.disposableStore.add(extRegResult.registerFileUrl(entry[0], verifyUrlOrCreateDataUrl(entry[1])));
251
- }
252
- }
253
- allPromises.push(extRegResult.whenReady());
269
+ allPromises.push(this.initExtension(extensionConfig, extensionIds));
254
270
  }
255
271
  }
256
272
  await Promise.all(allPromises);
257
273
  }
258
274
  }
259
275
 
276
+ protected initExtension(extensionConfig: ExtensionConfig, extensionIds: string[]): Promise<void> {
277
+ if (!extensionIds.includes(`${extensionConfig.config.publisher}.${extensionConfig.config.name}`)) {
278
+ const manifest = extensionConfig.config as IExtensionManifest;
279
+ const extRegResult = registerExtension(manifest, ExtensionHostKind.LocalProcess);
280
+ this.extensionRegisterResults.set(manifest.name, extRegResult);
281
+ if (extensionConfig.filesOrContents && Object.hasOwn(extRegResult, 'registerFileUrl')) {
282
+ for (const entry of extensionConfig.filesOrContents) {
283
+ this.disposableStore.add(extRegResult.registerFileUrl(entry[0], encodeStringOrUrlToDataUrl(entry[1])));
284
+ }
285
+ }
286
+ return extRegResult.whenReady();
287
+ } else {
288
+ return Promise.resolve();
289
+ }
290
+ }
291
+
260
292
  protected markGlobalInit() {
261
293
  this.logger.debug('markGlobalInit');
262
294
 
@@ -268,33 +300,41 @@ export class MonacoVscodeApiWrapper {
268
300
 
269
301
  protected markGlobalInitDone() {
270
302
  const envEnhanced = getEnhancedMonacoEnvironment();
271
- if (typeof envEnhanced.vscodeApiGlobalInitResolve === 'function') {
272
- envEnhanced.vscodeApiGlobalInitResolve();
273
- }
303
+ envEnhanced.vscodeApiGlobalInitResolve?.();
304
+
274
305
  envEnhanced.vscodeApiInitialised = true;
275
306
  envEnhanced.vscodeApiGlobalInitAwait = undefined;
276
307
  envEnhanced.vscodeApiGlobalInitResolve = undefined;
277
308
  this.logger.debug('markGlobalInitDone');
278
309
  }
279
310
 
280
- async init(instructions?: InitServicesInstructions): Promise<void> {
311
+ overrideViewsConfig(viewsConfigOverride: ViewsConfigRuntime) {
312
+ const orgViewsConfig = this.apiConfig.viewsConfig;
313
+ this.apiConfig.viewsConfig = {
314
+ $type: viewsConfigOverride.$type,
315
+ htmlContainer: viewsConfigOverride.htmlContainer,
316
+ htmlAugmentationInstructions: viewsConfigOverride.htmlAugmentationInstructions ?? orgViewsConfig.htmlAugmentationInstructions,
317
+ openEditorFunc: viewsConfigOverride.openEditorFunc ?? orgViewsConfig.openEditorFunc,
318
+ viewsInitFunc: viewsConfigOverride.viewsInitFunc ?? orgViewsConfig.viewsInitFunc
319
+ };
320
+ }
321
+
322
+ async start(startInstructions?: StartInstructions): Promise<void> {
281
323
  const envEnhanced = getEnhancedMonacoEnvironment();
282
324
  if (envEnhanced.vscodeApiInitialised === true) {
283
325
  this.logger.warn('Initialization of monaco-vscode api can only performed once!');
284
326
  } else {
285
327
  if (!(envEnhanced.vscodeApiInitialising === true)) {
328
+
286
329
  envEnhanced.vscodeApiInitialising = true;
287
330
  this.markGlobalInit();
288
- if (instructions?.htmlContainer !== undefined && instructions.htmlContainer !== null) {
289
- this.apiConfig.htmlContainer = instructions.htmlContainer;
290
- }
291
331
 
292
332
  // ensures "vscodeApiConfig.workspaceConfig" is available
293
333
  this.configureWorkspaceConfig();
294
334
 
295
335
  // ensure logging and development logging options are in-line
296
336
  this.configureDevLogLevel();
297
- this.logger.info(`Initializing monaco-vscode api. Caller: ${instructions?.caller ?? 'unknown'}`);
337
+ this.logger.info(`Initializing monaco-vscode api. Caller: ${startInstructions?.caller ?? 'unknown'}`);
298
338
 
299
339
  await this.configureMonacoWorkers();
300
340
 
@@ -304,12 +344,12 @@ export class MonacoVscodeApiWrapper {
304
344
  // ensure one of the three potential view services are configured
305
345
  await this.configureViewsServices();
306
346
 
307
- // enforece semantic highlighting if configured
347
+ // enforce semantic highlighting if configured
308
348
  this.configureSemanticHighlighting();
309
349
 
310
350
  await this.initUserConfiguration();
311
351
 
312
- await this.importAllServices(instructions);
352
+ await this.initAllServices(startInstructions?.performServiceConsistencyChecks);
313
353
 
314
354
  await this.applyViewsPostConfig();
315
355
 
@@ -1,5 +1,5 @@
1
1
  /* --------------------------------------------------------------------------------------------
2
- * Copyright (c) 2024 TypeFox and others.
2
+ * Copyright (c) 2025 TypeFox and others.
3
3
  * Licensed under the MIT License. See LICENSE in the package root for license information.
4
4
  * ------------------------------------------------------------------------------------------ */
5
5
 
@@ -11,21 +11,27 @@ import type { EnvironmentOverride } from '@codingame/monaco-vscode-api/workbench
11
11
  import type { OpenEditor } from '@codingame/monaco-vscode-editor-service-override';
12
12
  import type { Logger } from 'monaco-languageclient/common';
13
13
 
14
+ export type OverallConfigType = 'extended' | 'classic';
15
+
16
+ export type ViewsConfigTypes = 'EditorService' | 'ViewsService' | 'WorkspaceService';
17
+
18
+ export type HtmlContainerConfig = HTMLElement | 'ReactPlaceholder';
19
+
14
20
  export interface MonacoEnvironmentEnhanced extends monaco.Environment {
15
21
  vscodeApiInitialising?: boolean;
16
22
  vscodeApiInitialised?: boolean;
17
23
  vscodeApiGlobalInitAwait?: Promise<void>;
18
24
  vscodeApiGlobalInitResolve?: ((value: void | PromiseLike<void>) => void);
19
- viewServiceType?: 'EditorService' | 'ViewsService' | 'WorkspaceService';
25
+ viewServiceType?: ViewsConfigTypes;
20
26
  }
21
27
 
22
- export type OverallConfigType = 'extended' | 'classic';
23
-
24
28
  export interface UserConfiguration {
25
29
  json?: string;
26
30
  }
31
+
27
32
  export interface ViewsConfig {
28
- viewServiceType: 'EditorService' | 'ViewsService' | 'WorkspaceService';
33
+ $type: ViewsConfigTypes;
34
+ htmlContainer: HtmlContainerConfig;
29
35
  openEditorFunc?: OpenEditor;
30
36
  htmlAugmentationInstructions?: (htmlContainer: HTMLElement | null | undefined) => void;
31
37
  viewsInitFunc?: () => Promise<void>;
@@ -38,12 +44,11 @@ export interface ExtensionConfig {
38
44
 
39
45
  export interface MonacoVscodeApiConfig {
40
46
  $type: OverallConfigType;
41
- htmlContainer?: HTMLElement;
42
- serviceOverrides: monaco.editor.IEditorOverrideServices;
47
+ viewsConfig: ViewsConfig,
48
+ serviceOverrides?: monaco.editor.IEditorOverrideServices;
43
49
  logLevel?: LogLevel | number;
44
50
  workspaceConfig?: IWorkbenchConstructionOptions;
45
51
  userConfiguration?: UserConfiguration;
46
- viewsConfig?: ViewsConfig,
47
52
  envOptions?: EnvironmentOverride;
48
53
  extensions?: ExtensionConfig[];
49
54
  monacoWorkerFactory?: (logger?: Logger) => void;