@adecore/editor 0.26.2 → 0.27.0

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.
@@ -10,6 +10,9 @@ export type DiffSyntaxInput = {
10
10
  readonly type: 'start';
11
11
  readonly themes: readonly ThemeRegistration[];
12
12
  readonly maxLines: number;
13
+ } | {
14
+ readonly type: 'themes';
15
+ readonly themes: readonly ThemeRegistration[];
13
16
  } | {
14
17
  readonly type: 'request';
15
18
  readonly generation: number;
@@ -39,6 +39,15 @@ function packedTokens(generation, index, code, tokens, appearance) {
39
39
  lines[tokens.length] = cursor / 3;
40
40
  return { type: 'tokens', generation, index, colors, ...appearance, lines, tokens: packed };
41
41
  }
42
+ /* Loads only the themes the highlighter lacks by name, so one another user of a borrowed highlighter loaded keeps its identity. */
43
+ async function loadMissingThemes(loaded, themes) {
44
+ const known = new Set(loaded.getLoadedThemes());
45
+ const missing = themes.filter((theme) => theme.name === undefined || !known.has(theme.name));
46
+ if (missing.length > 0) {
47
+ await loaded.loadTheme(...missing);
48
+ }
49
+ return loaded;
50
+ }
42
51
  /* The packet omits text and token lengths; its source line supplies the final token's end. */
43
52
  export function lineTokensOf(packet, line, text) {
44
53
  if (!Number.isInteger(line) || line < 0 || line + 1 >= packet.lines.length) {
@@ -193,16 +202,17 @@ export function createSyntaxService(options) {
193
202
  }
194
203
  entries.clear();
195
204
  count = 0;
196
- ready = options.highlighter().then(async (loaded) => {
197
- const known = new Set(loaded.getLoadedThemes());
198
- const missing = message.themes.filter((theme) => theme.name === undefined || !known.has(theme.name));
199
- if (missing.length > 0) {
200
- await loaded.loadTheme(...missing);
201
- }
202
- return loaded;
203
- });
205
+ ready = options.highlighter().then((loaded) => loadMissingThemes(loaded, message.themes));
204
206
  return ready.then(() => options.send({ type: 'ready' }), (error) => options.send({ type: 'error', message: error instanceof Error ? error.message : String(error) }));
205
207
  }
208
+ if (message.type === 'themes') {
209
+ // The queue awaits `ready` anew for every request, so a request sent after this one draws in these themes.
210
+ ready = (ready ?? options.highlighter()).then((loaded) =>
211
+ // A theme that fails to load fails only the requests drawn in it, never the ones in themes already in.
212
+ loadMissingThemes(loaded, message.themes).catch(() => loaded));
213
+ // A failed start has already reported its error.
214
+ return ready.then(() => undefined, () => undefined);
215
+ }
206
216
  if (message.type === 'cancel' || message.type === 'dispose') {
207
217
  cancel(message.generation);
208
218
  if (message.type === 'dispose') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/editor",
3
- "version": "0.26.2",
3
+ "version": "0.27.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -54,7 +54,7 @@
54
54
  "test": "bun test --conditions=source"
55
55
  },
56
56
  "dependencies": {
57
- "@adecore/editor-core": "0.26.2",
57
+ "@adecore/editor-core": "0.27.0",
58
58
  "linkedom": "^0.18.13",
59
59
  "shiki": "^4.4.3"
60
60
  },
@@ -12,6 +12,7 @@ export interface DiffSyntaxDocument {
12
12
 
13
13
  export type DiffSyntaxInput =
14
14
  | { readonly type: 'start'; readonly themes: readonly ThemeRegistration[]; readonly maxLines: number }
15
+ | { readonly type: 'themes'; readonly themes: readonly ThemeRegistration[] }
15
16
  | { readonly type: 'request'; readonly generation: number; readonly index: number; readonly document?: DiffSyntaxDocument }
16
17
  | { readonly type: 'cancel'; readonly generation: number }
17
18
  | { readonly type: 'dispose'; readonly generation: number };
@@ -106,6 +107,16 @@ function packedTokens(
106
107
  return { type: 'tokens', generation, index, colors, ...appearance, lines, tokens: packed };
107
108
  }
108
109
 
110
+ /* Loads only the themes the highlighter lacks by name, so one another user of a borrowed highlighter loaded keeps its identity. */
111
+ async function loadMissingThemes(loaded: Highlighter, themes: readonly ThemeRegistration[]): Promise<Highlighter> {
112
+ const known = new Set(loaded.getLoadedThemes());
113
+ const missing = themes.filter((theme) => theme.name === undefined || !known.has(theme.name));
114
+ if (missing.length > 0) {
115
+ await loaded.loadTheme(...missing);
116
+ }
117
+ return loaded;
118
+ }
119
+
109
120
  /* The packet omits text and token lengths; its source line supplies the final token's end. */
110
121
  export function lineTokensOf(packet: DiffSyntaxTokens, line: number, text: string): LineToken[] {
111
122
  if (!Number.isInteger(line) || line < 0 || line + 1 >= packet.lines.length) {
@@ -259,19 +270,24 @@ export function createSyntaxService(options: DiffSyntaxServiceOptions): DiffSynt
259
270
  }
260
271
  entries.clear();
261
272
  count = 0;
262
- ready = options.highlighter().then(async (loaded) => {
263
- const known = new Set(loaded.getLoadedThemes());
264
- const missing = message.themes.filter((theme) => theme.name === undefined || !known.has(theme.name));
265
- if (missing.length > 0) {
266
- await loaded.loadTheme(...missing);
267
- }
268
- return loaded;
269
- });
273
+ ready = options.highlighter().then((loaded) => loadMissingThemes(loaded, message.themes));
270
274
  return ready.then(
271
275
  () => options.send({ type: 'ready' }),
272
276
  (error: unknown) => options.send({ type: 'error', message: error instanceof Error ? error.message : String(error) })
273
277
  );
274
278
  }
279
+ if (message.type === 'themes') {
280
+ // The queue awaits `ready` anew for every request, so a request sent after this one draws in these themes.
281
+ ready = (ready ?? options.highlighter()).then((loaded) =>
282
+ // A theme that fails to load fails only the requests drawn in it, never the ones in themes already in.
283
+ loadMissingThemes(loaded, message.themes).catch(() => loaded)
284
+ );
285
+ // A failed start has already reported its error.
286
+ return ready.then(
287
+ () => undefined,
288
+ () => undefined
289
+ );
290
+ }
275
291
  if (message.type === 'cancel' || message.type === 'dispose') {
276
292
  cancel(message.generation);
277
293
  if (message.type === 'dispose') {