@shikijs/core 1.15.2 → 1.16.1

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.
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { INITIAL, StackElementMetadata, Registry as Registry$1, Theme } from './textmate.mjs';
2
1
  import { FontStyle } from './types.mjs';
2
+ import { INITIAL, EncodedTokenMetadata, Registry as Registry$1, Theme } from '@shikijs/vscode-textmate';
3
+ export { EncodedTokenMetadata as StackElementMetadata } from '@shikijs/vscode-textmate';
3
4
 
4
5
  function toArray(x) {
5
6
  return Array.isArray(x) ? x : [x];
@@ -121,6 +122,12 @@ function splitTokens(tokens, breakpoints) {
121
122
  });
122
123
  });
123
124
  }
125
+ /**
126
+ * Normalize a getter to a promise.
127
+ */
128
+ async function normalizeGetter(p) {
129
+ return Promise.resolve(typeof p === 'function' ? p() : p).then(r => r.default || r);
130
+ }
124
131
  function resolveColorReplacements(theme, options) {
125
132
  const replacements = typeof theme === 'string' ? {} : { ...theme.colorReplacements };
126
133
  const themeName = typeof theme === 'string' ? theme : theme.name;
@@ -194,6 +201,248 @@ function createPositionConverter(code) {
194
201
  };
195
202
  }
196
203
 
204
+ class ShikiError extends Error {
205
+ constructor(message) {
206
+ super(message);
207
+ this.name = 'ShikiError';
208
+ }
209
+ }
210
+
211
+ /**
212
+ * A built-in transformer to add decorations to the highlighted code.
213
+ */
214
+ function transformerDecorations() {
215
+ const map = new WeakMap();
216
+ function getContext(shiki) {
217
+ if (!map.has(shiki.meta)) {
218
+ const converter = createPositionConverter(shiki.source);
219
+ function normalizePosition(p) {
220
+ if (typeof p === 'number') {
221
+ if (p < 0 || p > shiki.source.length)
222
+ throw new ShikiError(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`);
223
+ return {
224
+ ...converter.indexToPos(p),
225
+ offset: p,
226
+ };
227
+ }
228
+ else {
229
+ const line = converter.lines[p.line];
230
+ if (line === undefined)
231
+ throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`);
232
+ if (p.character < 0 || p.character > line.length)
233
+ throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`);
234
+ return {
235
+ ...p,
236
+ offset: converter.posToIndex(p.line, p.character),
237
+ };
238
+ }
239
+ }
240
+ const decorations = (shiki.options.decorations || [])
241
+ .map((d) => ({
242
+ ...d,
243
+ start: normalizePosition(d.start),
244
+ end: normalizePosition(d.end),
245
+ }));
246
+ verifyIntersections(decorations);
247
+ map.set(shiki.meta, {
248
+ decorations,
249
+ converter,
250
+ source: shiki.source,
251
+ });
252
+ }
253
+ return map.get(shiki.meta);
254
+ }
255
+ return {
256
+ name: 'shiki:decorations',
257
+ tokens(tokens) {
258
+ if (!this.options.decorations?.length)
259
+ return;
260
+ const ctx = getContext(this);
261
+ const breakpoints = ctx.decorations.flatMap(d => [d.start.offset, d.end.offset]);
262
+ const splitted = splitTokens(tokens, breakpoints);
263
+ return splitted;
264
+ },
265
+ code(codeEl) {
266
+ if (!this.options.decorations?.length)
267
+ return;
268
+ const ctx = getContext(this);
269
+ const lines = Array.from(codeEl.children).filter(i => i.type === 'element' && i.tagName === 'span');
270
+ if (lines.length !== ctx.converter.lines.length)
271
+ throw new ShikiError(`Number of lines in code element (${lines.length}) does not match the number of lines in the source (${ctx.converter.lines.length}). Failed to apply decorations.`);
272
+ function applyLineSection(line, start, end, decoration) {
273
+ const lineEl = lines[line];
274
+ let text = '';
275
+ let startIndex = -1;
276
+ let endIndex = -1;
277
+ if (start === 0)
278
+ startIndex = 0;
279
+ if (end === 0)
280
+ endIndex = 0;
281
+ if (end === Number.POSITIVE_INFINITY)
282
+ endIndex = lineEl.children.length;
283
+ if (startIndex === -1 || endIndex === -1) {
284
+ for (let i = 0; i < lineEl.children.length; i++) {
285
+ text += stringify$2(lineEl.children[i]);
286
+ if (startIndex === -1 && text.length === start)
287
+ startIndex = i + 1;
288
+ if (endIndex === -1 && text.length === end)
289
+ endIndex = i + 1;
290
+ }
291
+ }
292
+ if (startIndex === -1)
293
+ throw new ShikiError(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`);
294
+ if (endIndex === -1)
295
+ throw new ShikiError(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`);
296
+ const children = lineEl.children.slice(startIndex, endIndex);
297
+ // Full line decoration
298
+ if (!decoration.alwaysWrap && children.length === lineEl.children.length) {
299
+ applyDecoration(lineEl, decoration, 'line');
300
+ }
301
+ // Single token decoration
302
+ else if (!decoration.alwaysWrap && children.length === 1 && children[0].type === 'element') {
303
+ applyDecoration(children[0], decoration, 'token');
304
+ }
305
+ // Create a wrapper for the decoration
306
+ else {
307
+ const wrapper = {
308
+ type: 'element',
309
+ tagName: 'span',
310
+ properties: {},
311
+ children,
312
+ };
313
+ applyDecoration(wrapper, decoration, 'wrapper');
314
+ lineEl.children.splice(startIndex, children.length, wrapper);
315
+ }
316
+ }
317
+ function applyLine(line, decoration) {
318
+ lines[line] = applyDecoration(lines[line], decoration, 'line');
319
+ }
320
+ function applyDecoration(el, decoration, type) {
321
+ const properties = decoration.properties || {};
322
+ const transform = decoration.transform || (i => i);
323
+ el.tagName = decoration.tagName || 'span';
324
+ el.properties = {
325
+ ...el.properties,
326
+ ...properties,
327
+ class: el.properties.class,
328
+ };
329
+ if (decoration.properties?.class)
330
+ addClassToHast(el, decoration.properties.class);
331
+ el = transform(el, type) || el;
332
+ return el;
333
+ }
334
+ const lineApplies = [];
335
+ // Apply decorations in reverse order so the nested ones get applied first.
336
+ const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset);
337
+ for (const decoration of sorted) {
338
+ const { start, end } = decoration;
339
+ if (start.line === end.line) {
340
+ applyLineSection(start.line, start.character, end.character, decoration);
341
+ }
342
+ else if (start.line < end.line) {
343
+ applyLineSection(start.line, start.character, Number.POSITIVE_INFINITY, decoration);
344
+ for (let i = start.line + 1; i < end.line; i++)
345
+ lineApplies.unshift(() => applyLine(i, decoration));
346
+ applyLineSection(end.line, 0, end.character, decoration);
347
+ }
348
+ }
349
+ lineApplies.forEach(i => i());
350
+ },
351
+ };
352
+ }
353
+ function verifyIntersections(items) {
354
+ for (let i = 0; i < items.length; i++) {
355
+ const foo = items[i];
356
+ if (foo.start.offset > foo.end.offset)
357
+ throw new ShikiError(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`);
358
+ for (let j = i + 1; j < items.length; j++) {
359
+ const bar = items[j];
360
+ const isFooHasBarStart = foo.start.offset < bar.start.offset && bar.start.offset < foo.end.offset;
361
+ const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset < foo.end.offset;
362
+ const isBarHasFooStart = bar.start.offset < foo.start.offset && foo.start.offset < bar.end.offset;
363
+ const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset < bar.end.offset;
364
+ if (isFooHasBarStart || isFooHasBarEnd || isBarHasFooStart || isBarHasFooEnd) {
365
+ if (isFooHasBarEnd && isFooHasBarEnd)
366
+ continue; // nested
367
+ if (isBarHasFooStart && isBarHasFooEnd)
368
+ continue; // nested
369
+ throw new ShikiError(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`);
370
+ }
371
+ }
372
+ }
373
+ }
374
+ function stringify$2(el) {
375
+ if (el.type === 'text')
376
+ return el.value;
377
+ if (el.type === 'element')
378
+ return el.children.map(stringify$2).join('');
379
+ return '';
380
+ }
381
+
382
+ const builtInTransformers = [
383
+ /* @__PURE__ */ transformerDecorations(),
384
+ ];
385
+ function getTransformers(options) {
386
+ return [
387
+ ...options.transformers || [],
388
+ ...builtInTransformers,
389
+ ];
390
+ }
391
+
392
+ /**
393
+ * GrammarState is a special reference object that holds the state of a grammar.
394
+ *
395
+ * It's used to highlight code snippets that are part of the target language.
396
+ */
397
+ class GrammarState {
398
+ _stack;
399
+ lang;
400
+ theme;
401
+ /**
402
+ * Static method to create a initial grammar state.
403
+ */
404
+ static initial(lang, theme) {
405
+ return new GrammarState(INITIAL, lang, theme);
406
+ }
407
+ constructor(_stack, lang, theme) {
408
+ this._stack = _stack;
409
+ this.lang = lang;
410
+ this.theme = theme;
411
+ }
412
+ get scopes() {
413
+ return getScopes(this._stack);
414
+ }
415
+ toJSON() {
416
+ return {
417
+ lang: this.lang,
418
+ theme: this.theme,
419
+ scopes: this.scopes,
420
+ };
421
+ }
422
+ }
423
+ function getScopes(stack) {
424
+ const scopes = [];
425
+ const visited = new Set();
426
+ function pushScope(stack) {
427
+ if (visited.has(stack))
428
+ return;
429
+ visited.add(stack);
430
+ const name = stack?.nameScopesList?.scopeName;
431
+ if (name)
432
+ scopes.push(name);
433
+ if (stack.parent)
434
+ pushScope(stack.parent);
435
+ }
436
+ pushScope(stack);
437
+ return scopes;
438
+ }
439
+ function getGrammarStack(state) {
440
+ if (!(state instanceof GrammarState))
441
+ throw new ShikiError('Invalid grammar state');
442
+ // @ts-expect-error _stack is private
443
+ return state._stack;
444
+ }
445
+
197
446
  // src/colors.ts
198
447
  var namedColors = [
199
448
  "black",
@@ -525,67 +774,9 @@ function dimColor(color) {
525
774
  return color;
526
775
  }
527
776
 
528
- class ShikiError extends Error {
529
- constructor(message) {
530
- super(message);
531
- this.name = 'ShikiError';
532
- }
533
- }
534
-
535
- /**
536
- * GrammarState is a special reference object that holds the state of a grammar.
537
- *
538
- * It's used to highlight code snippets that are part of the target language.
539
- */
540
- class GrammarState {
541
- _stack;
542
- lang;
543
- theme;
544
- /**
545
- * Static method to create a initial grammar state.
546
- */
547
- static initial(lang, theme) {
548
- return new GrammarState(INITIAL, lang, theme);
549
- }
550
- constructor(_stack, lang, theme) {
551
- this._stack = _stack;
552
- this.lang = lang;
553
- this.theme = theme;
554
- }
555
- get scopes() {
556
- return getScopes(this._stack);
557
- }
558
- toJSON() {
559
- return {
560
- lang: this.lang,
561
- theme: this.theme,
562
- scopes: this.scopes,
563
- };
564
- }
565
- }
566
- function getScopes(stack) {
567
- const scopes = [];
568
- const visited = new Set();
569
- function pushScope(stack) {
570
- if (visited.has(stack))
571
- return;
572
- visited.add(stack);
573
- const name = stack?.nameScopesList?.scopeName;
574
- if (name)
575
- scopes.push(name);
576
- if (stack.parent)
577
- pushScope(stack.parent);
578
- }
579
- pushScope(stack);
580
- return scopes;
581
- }
582
- function getGrammarStack(state) {
583
- if (!(state instanceof GrammarState))
584
- throw new ShikiError('Invalid grammar state');
585
- // @ts-expect-error _stack is private
586
- return state._stack;
587
- }
588
-
777
+ /* ---------------------------------------------------------
778
+ * Copyright (C) Microsoft Corporation. All rights reserved.
779
+ *-------------------------------------------------------- */
589
780
  /**
590
781
  * Code to tokens, with a simple theme.
591
782
  */
@@ -669,8 +860,8 @@ function _tokenizeWithTheme(code, grammar, theme, colorMap, options) {
669
860
  if (startIndex === nextStartIndex)
670
861
  continue;
671
862
  const metadata = result.tokens[2 * j + 1];
672
- const color = applyColorReplacements(colorMap[StackElementMetadata.getForeground(metadata)], colorReplacements);
673
- const fontStyle = StackElementMetadata.getFontStyle(metadata);
863
+ const color = applyColorReplacements(colorMap[EncodedTokenMetadata.getForeground(metadata)], colorReplacements);
864
+ const fontStyle = EncodedTokenMetadata.getFontStyle(metadata);
674
865
  const token = {
675
866
  content: line.substring(startIndex, nextStartIndex),
676
867
  offset: lineOffset + startIndex,
@@ -934,187 +1125,6 @@ function mergeToken(merged, variantsOrder, cssVariablePrefix, defaultColor) {
934
1125
  return token;
935
1126
  }
936
1127
 
937
- /**
938
- * A built-in transformer to add decorations to the highlighted code.
939
- */
940
- function transformerDecorations() {
941
- const map = new WeakMap();
942
- function getContext(shiki) {
943
- if (!map.has(shiki.meta)) {
944
- const converter = createPositionConverter(shiki.source);
945
- function normalizePosition(p) {
946
- if (typeof p === 'number') {
947
- if (p < 0 || p > shiki.source.length)
948
- throw new ShikiError(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`);
949
- return {
950
- ...converter.indexToPos(p),
951
- offset: p,
952
- };
953
- }
954
- else {
955
- const line = converter.lines[p.line];
956
- if (line === undefined)
957
- throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`);
958
- if (p.character < 0 || p.character > line.length)
959
- throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`);
960
- return {
961
- ...p,
962
- offset: converter.posToIndex(p.line, p.character),
963
- };
964
- }
965
- }
966
- const decorations = (shiki.options.decorations || [])
967
- .map((d) => ({
968
- ...d,
969
- start: normalizePosition(d.start),
970
- end: normalizePosition(d.end),
971
- }));
972
- verifyIntersections(decorations);
973
- map.set(shiki.meta, {
974
- decorations,
975
- converter,
976
- source: shiki.source,
977
- });
978
- }
979
- return map.get(shiki.meta);
980
- }
981
- return {
982
- name: 'shiki:decorations',
983
- tokens(tokens) {
984
- if (!this.options.decorations?.length)
985
- return;
986
- const ctx = getContext(this);
987
- const breakpoints = ctx.decorations.flatMap(d => [d.start.offset, d.end.offset]);
988
- const splitted = splitTokens(tokens, breakpoints);
989
- return splitted;
990
- },
991
- code(codeEl) {
992
- if (!this.options.decorations?.length)
993
- return;
994
- const ctx = getContext(this);
995
- const lines = Array.from(codeEl.children).filter(i => i.type === 'element' && i.tagName === 'span');
996
- if (lines.length !== ctx.converter.lines.length)
997
- throw new ShikiError(`Number of lines in code element (${lines.length}) does not match the number of lines in the source (${ctx.converter.lines.length}). Failed to apply decorations.`);
998
- function applyLineSection(line, start, end, decoration) {
999
- const lineEl = lines[line];
1000
- let text = '';
1001
- let startIndex = -1;
1002
- let endIndex = -1;
1003
- if (start === 0)
1004
- startIndex = 0;
1005
- if (end === 0)
1006
- endIndex = 0;
1007
- if (end === Number.POSITIVE_INFINITY)
1008
- endIndex = lineEl.children.length;
1009
- if (startIndex === -1 || endIndex === -1) {
1010
- for (let i = 0; i < lineEl.children.length; i++) {
1011
- text += stringify$2(lineEl.children[i]);
1012
- if (startIndex === -1 && text.length === start)
1013
- startIndex = i + 1;
1014
- if (endIndex === -1 && text.length === end)
1015
- endIndex = i + 1;
1016
- }
1017
- }
1018
- if (startIndex === -1)
1019
- throw new ShikiError(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`);
1020
- if (endIndex === -1)
1021
- throw new ShikiError(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`);
1022
- const children = lineEl.children.slice(startIndex, endIndex);
1023
- // Full line decoration
1024
- if (!decoration.alwaysWrap && children.length === lineEl.children.length) {
1025
- applyDecoration(lineEl, decoration, 'line');
1026
- }
1027
- // Single token decoration
1028
- else if (!decoration.alwaysWrap && children.length === 1 && children[0].type === 'element') {
1029
- applyDecoration(children[0], decoration, 'token');
1030
- }
1031
- // Create a wrapper for the decoration
1032
- else {
1033
- const wrapper = {
1034
- type: 'element',
1035
- tagName: 'span',
1036
- properties: {},
1037
- children,
1038
- };
1039
- applyDecoration(wrapper, decoration, 'wrapper');
1040
- lineEl.children.splice(startIndex, children.length, wrapper);
1041
- }
1042
- }
1043
- function applyLine(line, decoration) {
1044
- lines[line] = applyDecoration(lines[line], decoration, 'line');
1045
- }
1046
- function applyDecoration(el, decoration, type) {
1047
- const properties = decoration.properties || {};
1048
- const transform = decoration.transform || (i => i);
1049
- el.tagName = decoration.tagName || 'span';
1050
- el.properties = {
1051
- ...el.properties,
1052
- ...properties,
1053
- class: el.properties.class,
1054
- };
1055
- if (decoration.properties?.class)
1056
- addClassToHast(el, decoration.properties.class);
1057
- el = transform(el, type) || el;
1058
- return el;
1059
- }
1060
- const lineApplies = [];
1061
- // Apply decorations in reverse order so the nested ones get applied first.
1062
- const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset);
1063
- for (const decoration of sorted) {
1064
- const { start, end } = decoration;
1065
- if (start.line === end.line) {
1066
- applyLineSection(start.line, start.character, end.character, decoration);
1067
- }
1068
- else if (start.line < end.line) {
1069
- applyLineSection(start.line, start.character, Number.POSITIVE_INFINITY, decoration);
1070
- for (let i = start.line + 1; i < end.line; i++)
1071
- lineApplies.unshift(() => applyLine(i, decoration));
1072
- applyLineSection(end.line, 0, end.character, decoration);
1073
- }
1074
- }
1075
- lineApplies.forEach(i => i());
1076
- },
1077
- };
1078
- }
1079
- function verifyIntersections(items) {
1080
- for (let i = 0; i < items.length; i++) {
1081
- const foo = items[i];
1082
- if (foo.start.offset > foo.end.offset)
1083
- throw new ShikiError(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`);
1084
- for (let j = i + 1; j < items.length; j++) {
1085
- const bar = items[j];
1086
- const isFooHasBarStart = foo.start.offset < bar.start.offset && bar.start.offset < foo.end.offset;
1087
- const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset < foo.end.offset;
1088
- const isBarHasFooStart = bar.start.offset < foo.start.offset && foo.start.offset < bar.end.offset;
1089
- const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset < bar.end.offset;
1090
- if (isFooHasBarStart || isFooHasBarEnd || isBarHasFooStart || isBarHasFooEnd) {
1091
- if (isFooHasBarEnd && isFooHasBarEnd)
1092
- continue; // nested
1093
- if (isBarHasFooStart && isBarHasFooEnd)
1094
- continue; // nested
1095
- throw new ShikiError(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`);
1096
- }
1097
- }
1098
- }
1099
- }
1100
- function stringify$2(el) {
1101
- if (el.type === 'text')
1102
- return el.value;
1103
- if (el.type === 'element')
1104
- return el.children.map(stringify$2).join('');
1105
- return '';
1106
- }
1107
-
1108
- const builtInTransformers = [
1109
- /* @__PURE__ */ transformerDecorations(),
1110
- ];
1111
- function getTransformers(options) {
1112
- return [
1113
- ...options.transformers || [],
1114
- ...builtInTransformers,
1115
- ];
1116
- }
1117
-
1118
1128
  function codeToHast(internal, code, options, transformerContext = {
1119
1129
  meta: {},
1120
1130
  options,
@@ -4690,423 +4700,103 @@ function codeToHtml(internal, code, options) {
4690
4700
  return result;
4691
4701
  }
4692
4702
 
4693
- /**
4694
- * https://github.com/microsoft/vscode/blob/f7f05dee53fb33fe023db2e06e30a89d3094488f/src/vs/platform/theme/common/colorRegistry.ts#L258-L268
4695
- */
4696
- const VSCODE_FALLBACK_EDITOR_FG = { light: '#333333', dark: '#bbbbbb' };
4697
- const VSCODE_FALLBACK_EDITOR_BG = { light: '#fffffe', dark: '#1e1e1e' };
4698
- const RESOLVED_KEY = '__shiki_resolved';
4699
- /**
4700
- * Normalize a textmate theme to shiki theme
4701
- */
4702
- function normalizeTheme(rawTheme) {
4703
- // @ts-expect-error private field
4704
- if (rawTheme?.[RESOLVED_KEY])
4705
- return rawTheme;
4706
- const theme = {
4707
- ...rawTheme,
4708
- };
4709
- // Fallback settings
4710
- if (theme.tokenColors && !theme.settings) {
4711
- theme.settings = theme.tokenColors;
4712
- delete theme.tokenColors;
4713
- }
4714
- theme.type ||= 'dark';
4715
- theme.colorReplacements = { ...theme.colorReplacements };
4716
- theme.settings ||= [];
4717
- // Guess fg/bg colors
4718
- let { bg, fg } = theme;
4719
- if (!bg || !fg) {
4720
- /**
4721
- * First try:
4722
- * Theme might contain a global `tokenColor` without `name` or `scope`
4723
- * Used as default value for foreground/background
4724
- */
4725
- const globalSetting = theme.settings
4726
- ? theme.settings.find((s) => !s.name && !s.scope)
4727
- : undefined;
4728
- if (globalSetting?.settings?.foreground)
4729
- fg = globalSetting.settings.foreground;
4730
- if (globalSetting?.settings?.background)
4731
- bg = globalSetting.settings.background;
4732
- /**
4733
- * Second try:
4734
- * If there's no global `tokenColor` without `name` or `scope`
4735
- * Use `editor.foreground` and `editor.background`
4736
- */
4737
- if (!fg && theme?.colors?.['editor.foreground'])
4738
- fg = theme.colors['editor.foreground'];
4739
- if (!bg && theme?.colors?.['editor.background'])
4740
- bg = theme.colors['editor.background'];
4741
- /**
4742
- * Last try:
4743
- * If there's no fg/bg color specified in theme, use default
4744
- */
4745
- if (!fg)
4746
- fg = theme.type === 'light' ? VSCODE_FALLBACK_EDITOR_FG.light : VSCODE_FALLBACK_EDITOR_FG.dark;
4747
- if (!bg)
4748
- bg = theme.type === 'light' ? VSCODE_FALLBACK_EDITOR_BG.light : VSCODE_FALLBACK_EDITOR_BG.dark;
4749
- theme.fg = fg;
4750
- theme.bg = bg;
4751
- }
4752
- // Push a no-scope setting with fallback colors
4753
- if (!(theme.settings[0] && theme.settings[0].settings && !theme.settings[0].scope)) {
4754
- theme.settings.unshift({
4755
- settings: {
4756
- foreground: theme.fg,
4757
- background: theme.bg,
4758
- },
4759
- });
4760
- }
4761
- // Push non-hex colors to color replacements, as `vscode-textmate` doesn't support them
4762
- let replacementCount = 0;
4763
- const replacementMap = new Map();
4764
- function getReplacementColor(value) {
4765
- if (replacementMap.has(value))
4766
- return replacementMap.get(value);
4767
- replacementCount += 1;
4768
- const hex = `#${replacementCount.toString(16).padStart(8, '0').toLowerCase()}`;
4769
- if (theme.colorReplacements?.[`#${hex}`]) // already exists
4770
- return getReplacementColor(value);
4771
- replacementMap.set(value, hex);
4772
- return hex;
4773
- }
4774
- theme.settings = theme.settings.map((setting) => {
4775
- const replaceFg = setting.settings?.foreground && !setting.settings.foreground.startsWith('#');
4776
- const replaceBg = setting.settings?.background && !setting.settings.background.startsWith('#');
4777
- if (!replaceFg && !replaceBg)
4778
- return setting;
4779
- const clone = {
4780
- ...setting,
4781
- settings: {
4782
- ...setting.settings,
4783
- },
4784
- };
4785
- if (replaceFg) {
4786
- const replacement = getReplacementColor(setting.settings.foreground);
4787
- theme.colorReplacements[replacement] = setting.settings.foreground;
4788
- clone.settings.foreground = replacement;
4789
- }
4790
- if (replaceBg) {
4791
- const replacement = getReplacementColor(setting.settings.background);
4792
- theme.colorReplacements[replacement] = setting.settings.background;
4793
- clone.settings.background = replacement;
4794
- }
4795
- return clone;
4796
- });
4797
- for (const key of Object.keys(theme.colors || {})) {
4798
- // Only patch for known keys
4799
- if (key === 'editor.foreground' || key === 'editor.background' || key.startsWith('terminal.ansi')) {
4800
- if (!theme.colors[key]?.startsWith('#')) {
4801
- const replacement = getReplacementColor(theme.colors[key]);
4802
- theme.colorReplacements[replacement] = theme.colors[key];
4803
- theme.colors[key] = replacement;
4804
- }
4805
- }
4806
- }
4807
- Object.defineProperty(theme, RESOLVED_KEY, {
4808
- enumerable: false,
4809
- writable: false,
4810
- value: true,
4811
- });
4812
- return theme;
4703
+ function getHeapMax() {
4704
+ return 2147483648;
4813
4705
  }
4814
-
4815
- class Registry extends Registry$1 {
4816
- _resolver;
4817
- _themes;
4818
- _langs;
4819
- _alias;
4820
- _resolvedThemes = new Map();
4821
- _resolvedGrammars = new Map();
4822
- _langMap = new Map();
4823
- _langGraph = new Map();
4824
- _textmateThemeCache = new WeakMap();
4825
- _loadedThemesCache = null;
4826
- _loadedLanguagesCache = null;
4827
- constructor(_resolver, _themes, _langs, _alias = {}) {
4828
- super(_resolver);
4829
- this._resolver = _resolver;
4830
- this._themes = _themes;
4831
- this._langs = _langs;
4832
- this._alias = _alias;
4833
- _themes.forEach(t => this.loadTheme(t));
4834
- _langs.forEach(l => this.loadLanguage(l));
4706
+ function _emscripten_get_now() {
4707
+ return typeof performance !== 'undefined' ? performance.now() : Date.now();
4708
+ }
4709
+ const alignUp = (x, multiple) => x + ((multiple - (x % multiple)) % multiple);
4710
+ async function main(init) {
4711
+ let wasmMemory;
4712
+ let buffer;
4713
+ const binding = {};
4714
+ function updateGlobalBufferAndViews(buf) {
4715
+ buffer = buf;
4716
+ binding.HEAPU8 = new Uint8Array(buf);
4717
+ binding.HEAPU32 = new Uint32Array(buf);
4835
4718
  }
4836
- getTheme(theme) {
4837
- if (typeof theme === 'string')
4838
- return this._resolvedThemes.get(theme);
4839
- else
4840
- return this.loadTheme(theme);
4719
+ function _emscripten_memcpy_big(dest, src, num) {
4720
+ binding.HEAPU8.copyWithin(dest, src, src + num);
4841
4721
  }
4842
- loadTheme(theme) {
4843
- const _theme = normalizeTheme(theme);
4844
- if (_theme.name) {
4845
- this._resolvedThemes.set(_theme.name, _theme);
4846
- // Reset cache
4847
- this._loadedThemesCache = null;
4722
+ function emscripten_realloc_buffer(size) {
4723
+ try {
4724
+ wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16);
4725
+ updateGlobalBufferAndViews(wasmMemory.buffer);
4726
+ return 1;
4848
4727
  }
4849
- return _theme;
4850
- }
4851
- getLoadedThemes() {
4852
- if (!this._loadedThemesCache)
4853
- this._loadedThemesCache = [...this._resolvedThemes.keys()];
4854
- return this._loadedThemesCache;
4728
+ catch { }
4855
4729
  }
4856
- // Override and re-implement this method to cache the textmate themes as `TextMateTheme.createFromRawTheme`
4857
- // is expensive. Themes can switch often especially for dual-theme support.
4858
- //
4859
- // The parent class also accepts `colorMap` as the second parameter, but since we don't use that,
4860
- // we omit here so it's easier to cache the themes.
4861
- setTheme(theme) {
4862
- let textmateTheme = this._textmateThemeCache.get(theme);
4863
- if (!textmateTheme) {
4864
- textmateTheme = Theme.createFromRawTheme(theme);
4865
- this._textmateThemeCache.set(theme, textmateTheme);
4730
+ function _emscripten_resize_heap(requestedSize) {
4731
+ const oldSize = binding.HEAPU8.length;
4732
+ requestedSize = requestedSize >>> 0;
4733
+ const maxHeapSize = getHeapMax();
4734
+ if (requestedSize > maxHeapSize)
4735
+ return false;
4736
+ for (let cutDown = 1; cutDown <= 4; cutDown *= 2) {
4737
+ let overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
4738
+ overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
4739
+ const newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
4740
+ const replacement = emscripten_realloc_buffer(newSize);
4741
+ if (replacement)
4742
+ return true;
4866
4743
  }
4867
- // @ts-expect-error Access private `_syncRegistry`, but should work in runtime
4868
- this._syncRegistry.setTheme(textmateTheme);
4744
+ return false;
4869
4745
  }
4870
- getGrammar(name) {
4871
- if (this._alias[name]) {
4872
- const resolved = new Set([name]);
4873
- while (this._alias[name]) {
4874
- name = this._alias[name];
4875
- if (resolved.has(name))
4876
- throw new ShikiError(`Circular alias \`${Array.from(resolved).join(' -> ')} -> ${name}\``);
4877
- resolved.add(name);
4746
+ const UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined;
4747
+ function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead = 1024) {
4748
+ const endIdx = idx + maxBytesToRead;
4749
+ let endPtr = idx;
4750
+ while (heapOrArray[endPtr] && !(endPtr >= endIdx))
4751
+ ++endPtr;
4752
+ if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
4753
+ return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
4754
+ }
4755
+ let str = '';
4756
+ while (idx < endPtr) {
4757
+ let u0 = heapOrArray[idx++];
4758
+ if (!(u0 & 128)) {
4759
+ str += String.fromCharCode(u0);
4760
+ continue;
4761
+ }
4762
+ const u1 = heapOrArray[idx++] & 63;
4763
+ if ((u0 & 224) === 192) {
4764
+ str += String.fromCharCode(((u0 & 31) << 6) | u1);
4765
+ continue;
4766
+ }
4767
+ const u2 = heapOrArray[idx++] & 63;
4768
+ if ((u0 & 240) === 224) {
4769
+ u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
4770
+ }
4771
+ else {
4772
+ u0 = ((u0 & 7) << 18)
4773
+ | (u1 << 12)
4774
+ | (u2 << 6)
4775
+ | (heapOrArray[idx++] & 63);
4776
+ }
4777
+ if (u0 < 65536) {
4778
+ str += String.fromCharCode(u0);
4779
+ }
4780
+ else {
4781
+ const ch = u0 - 65536;
4782
+ str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
4878
4783
  }
4879
4784
  }
4880
- return this._resolvedGrammars.get(name);
4785
+ return str;
4881
4786
  }
4882
- async loadLanguage(lang) {
4883
- if (this.getGrammar(lang.name))
4884
- return;
4885
- const embeddedLazilyBy = new Set([...this._langMap.values()]
4886
- .filter(i => i.embeddedLangsLazy?.includes(lang.name)));
4887
- this._resolver.addLanguage(lang);
4888
- const grammarConfig = {
4889
- balancedBracketSelectors: lang.balancedBracketSelectors || ['*'],
4890
- unbalancedBracketSelectors: lang.unbalancedBracketSelectors || [],
4891
- };
4892
- // @ts-expect-error Private members, set this to override the previous grammar (that can be a stub)
4893
- this._syncRegistry._rawGrammars.set(lang.scopeName, lang);
4894
- const g = await this.loadGrammarWithConfiguration(lang.scopeName, 1, grammarConfig);
4895
- g.name = lang.name;
4896
- this._resolvedGrammars.set(lang.name, g);
4897
- if (lang.aliases) {
4898
- lang.aliases.forEach((alias) => {
4899
- this._alias[alias] = lang.name;
4900
- });
4901
- }
4902
- // Reset cache
4903
- this._loadedLanguagesCache = null;
4904
- // If there is a language that embeds this language lazily, we need to reload it
4905
- if (embeddedLazilyBy.size) {
4906
- for (const e of embeddedLazilyBy) {
4907
- this._resolvedGrammars.delete(e.name);
4908
- // Reset cache
4909
- this._loadedLanguagesCache = null;
4910
- // @ts-expect-error clear cache
4911
- this._syncRegistry?._injectionGrammars?.delete(e.scopeName);
4912
- // @ts-expect-error clear cache
4913
- this._syncRegistry?._grammars?.delete(e.scopeName);
4914
- await this.loadLanguage(this._langMap.get(e.name));
4915
- }
4916
- }
4917
- }
4918
- async init() {
4919
- this._themes.map(t => this.loadTheme(t));
4920
- await this.loadLanguages(this._langs);
4921
- }
4922
- dispose() {
4923
- super.dispose();
4924
- this._resolvedThemes.clear();
4925
- this._resolvedGrammars.clear();
4926
- this._langMap.clear();
4927
- this._langGraph.clear();
4928
- this._loadedThemesCache = null;
4929
- }
4930
- async loadLanguages(langs) {
4931
- for (const lang of langs)
4932
- this.resolveEmbeddedLanguages(lang);
4933
- const langsGraphArray = Array.from(this._langGraph.entries());
4934
- const missingLangs = langsGraphArray.filter(([_, lang]) => !lang);
4935
- if (missingLangs.length) {
4936
- const dependents = langsGraphArray
4937
- .filter(([_, lang]) => lang && lang.embeddedLangs?.some(l => missingLangs.map(([name]) => name).includes(l)))
4938
- .filter(lang => !missingLangs.includes(lang));
4939
- throw new ShikiError(`Missing languages ${missingLangs.map(([name]) => `\`${name}\``).join(', ')}, required by ${dependents.map(([name]) => `\`${name}\``).join(', ')}`);
4940
- }
4941
- for (const [_, lang] of langsGraphArray)
4942
- this._resolver.addLanguage(lang);
4943
- for (const [_, lang] of langsGraphArray)
4944
- await this.loadLanguage(lang);
4945
- }
4946
- getLoadedLanguages() {
4947
- if (!this._loadedLanguagesCache) {
4948
- this._loadedLanguagesCache = [
4949
- ...new Set([...this._resolvedGrammars.keys(), ...Object.keys(this._alias)]),
4950
- ];
4951
- }
4952
- return this._loadedLanguagesCache;
4953
- }
4954
- resolveEmbeddedLanguages(lang) {
4955
- this._langMap.set(lang.name, lang);
4956
- this._langGraph.set(lang.name, lang);
4957
- if (lang.embeddedLangs) {
4958
- for (const embeddedLang of lang.embeddedLangs)
4959
- this._langGraph.set(embeddedLang, this._langMap.get(embeddedLang));
4960
- }
4961
- }
4962
- }
4963
-
4964
- class Resolver {
4965
- _langs = new Map();
4966
- _scopeToLang = new Map();
4967
- _injections = new Map();
4968
- _onigLibPromise;
4969
- constructor(onigLibPromise, langs) {
4970
- this._onigLibPromise = onigLibPromise
4971
- .then(engine => ({
4972
- createOnigScanner: patterns => engine.createScanner(patterns),
4973
- createOnigString: s => engine.createString(s),
4974
- }));
4975
- langs.forEach(i => this.addLanguage(i));
4976
- }
4977
- get onigLib() {
4978
- return this._onigLibPromise;
4979
- }
4980
- getLangRegistration(langIdOrAlias) {
4981
- return this._langs.get(langIdOrAlias);
4982
- }
4983
- async loadGrammar(scopeName) {
4984
- return this._scopeToLang.get(scopeName);
4985
- }
4986
- addLanguage(l) {
4987
- this._langs.set(l.name, l);
4988
- if (l.aliases) {
4989
- l.aliases.forEach((a) => {
4990
- this._langs.set(a, l);
4991
- });
4992
- }
4993
- this._scopeToLang.set(l.scopeName, l);
4994
- if (l.injectTo) {
4995
- l.injectTo.forEach((i) => {
4996
- if (!this._injections.get(i))
4997
- this._injections.set(i, []);
4998
- this._injections.get(i).push(l.scopeName);
4999
- });
5000
- }
5001
- }
5002
- getInjections(scopeName) {
5003
- const scopeParts = scopeName.split('.');
5004
- let injections = [];
5005
- for (let i = 1; i <= scopeParts.length; i++) {
5006
- const subScopeName = scopeParts.slice(0, i).join('.');
5007
- injections = [...injections, ...(this._injections.get(subScopeName) || [])];
5008
- }
5009
- return injections;
5010
- }
5011
- }
5012
-
5013
- function getHeapMax() {
5014
- return 2147483648;
5015
- }
5016
- function _emscripten_get_now() {
5017
- return typeof performance !== 'undefined' ? performance.now() : Date.now();
5018
- }
5019
- const alignUp = (x, multiple) => x + ((multiple - (x % multiple)) % multiple);
5020
- async function main(init) {
5021
- let wasmMemory;
5022
- let buffer;
5023
- const binding = {};
5024
- function updateGlobalBufferAndViews(buf) {
5025
- buffer = buf;
5026
- binding.HEAPU8 = new Uint8Array(buf);
5027
- binding.HEAPU32 = new Uint32Array(buf);
5028
- }
5029
- function _emscripten_memcpy_big(dest, src, num) {
5030
- binding.HEAPU8.copyWithin(dest, src, src + num);
5031
- }
5032
- function emscripten_realloc_buffer(size) {
5033
- try {
5034
- wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16);
5035
- updateGlobalBufferAndViews(wasmMemory.buffer);
5036
- return 1;
5037
- }
5038
- catch { }
5039
- }
5040
- function _emscripten_resize_heap(requestedSize) {
5041
- const oldSize = binding.HEAPU8.length;
5042
- requestedSize = requestedSize >>> 0;
5043
- const maxHeapSize = getHeapMax();
5044
- if (requestedSize > maxHeapSize)
5045
- return false;
5046
- for (let cutDown = 1; cutDown <= 4; cutDown *= 2) {
5047
- let overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
5048
- overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
5049
- const newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
5050
- const replacement = emscripten_realloc_buffer(newSize);
5051
- if (replacement)
5052
- return true;
5053
- }
5054
- return false;
5055
- }
5056
- const UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined;
5057
- function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead = 1024) {
5058
- const endIdx = idx + maxBytesToRead;
5059
- let endPtr = idx;
5060
- while (heapOrArray[endPtr] && !(endPtr >= endIdx))
5061
- ++endPtr;
5062
- if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
5063
- return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
5064
- }
5065
- let str = '';
5066
- while (idx < endPtr) {
5067
- let u0 = heapOrArray[idx++];
5068
- if (!(u0 & 128)) {
5069
- str += String.fromCharCode(u0);
5070
- continue;
5071
- }
5072
- const u1 = heapOrArray[idx++] & 63;
5073
- if ((u0 & 224) === 192) {
5074
- str += String.fromCharCode(((u0 & 31) << 6) | u1);
5075
- continue;
5076
- }
5077
- const u2 = heapOrArray[idx++] & 63;
5078
- if ((u0 & 240) === 224) {
5079
- u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
5080
- }
5081
- else {
5082
- u0 = ((u0 & 7) << 18)
5083
- | (u1 << 12)
5084
- | (u2 << 6)
5085
- | (heapOrArray[idx++] & 63);
5086
- }
5087
- if (u0 < 65536) {
5088
- str += String.fromCharCode(u0);
5089
- }
5090
- else {
5091
- const ch = u0 - 65536;
5092
- str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
5093
- }
5094
- }
5095
- return str;
5096
- }
5097
- function UTF8ToString(ptr, maxBytesToRead) {
5098
- return ptr ? UTF8ArrayToString(binding.HEAPU8, ptr, maxBytesToRead) : '';
5099
- }
5100
- const asmLibraryArg = {
5101
- emscripten_get_now: _emscripten_get_now,
5102
- emscripten_memcpy_big: _emscripten_memcpy_big,
5103
- emscripten_resize_heap: _emscripten_resize_heap,
5104
- fd_write: () => 0,
5105
- };
5106
- async function createWasm() {
5107
- const info = {
5108
- env: asmLibraryArg,
5109
- wasi_snapshot_preview1: asmLibraryArg,
4787
+ function UTF8ToString(ptr, maxBytesToRead) {
4788
+ return ptr ? UTF8ArrayToString(binding.HEAPU8, ptr, maxBytesToRead) : '';
4789
+ }
4790
+ const asmLibraryArg = {
4791
+ emscripten_get_now: _emscripten_get_now,
4792
+ emscripten_memcpy_big: _emscripten_memcpy_big,
4793
+ emscripten_resize_heap: _emscripten_resize_heap,
4794
+ fd_write: () => 0,
4795
+ };
4796
+ async function createWasm() {
4797
+ const info = {
4798
+ env: asmLibraryArg,
4799
+ wasi_snapshot_preview1: asmLibraryArg,
5110
4800
  };
5111
4801
  const exports = await init(info);
5112
4802
  wasmMemory = exports.memory;
@@ -5241,284 +4931,599 @@ class UtfString {
5241
4931
  this.utf16OffsetToUtf8 = utf16OffsetToUtf8;
5242
4932
  this.utf8OffsetToUtf16 = utf8OffsetToUtf16;
5243
4933
  }
5244
- createString(onigBinding) {
5245
- const result = onigBinding.omalloc(this.utf8Length);
5246
- onigBinding.HEAPU8.set(this.utf8Value, result);
5247
- return result;
4934
+ createString(onigBinding) {
4935
+ const result = onigBinding.omalloc(this.utf8Length);
4936
+ onigBinding.HEAPU8.set(this.utf8Value, result);
4937
+ return result;
4938
+ }
4939
+ }
4940
+ class OnigString {
4941
+ static LAST_ID = 0;
4942
+ static _sharedPtr = 0; // a pointer to a string of 10000 bytes
4943
+ static _sharedPtrInUse = false;
4944
+ id = (++OnigString.LAST_ID);
4945
+ _onigBinding;
4946
+ content;
4947
+ utf16Length;
4948
+ utf8Length;
4949
+ utf16OffsetToUtf8;
4950
+ utf8OffsetToUtf16;
4951
+ ptr;
4952
+ constructor(str) {
4953
+ if (!onigBinding)
4954
+ throw new ShikiError('Must invoke loadWasm first.');
4955
+ this._onigBinding = onigBinding;
4956
+ this.content = str;
4957
+ const utfString = new UtfString(str);
4958
+ this.utf16Length = utfString.utf16Length;
4959
+ this.utf8Length = utfString.utf8Length;
4960
+ this.utf16OffsetToUtf8 = utfString.utf16OffsetToUtf8;
4961
+ this.utf8OffsetToUtf16 = utfString.utf8OffsetToUtf16;
4962
+ if (this.utf8Length < 10000 && !OnigString._sharedPtrInUse) {
4963
+ if (!OnigString._sharedPtr)
4964
+ OnigString._sharedPtr = onigBinding.omalloc(10000);
4965
+ OnigString._sharedPtrInUse = true;
4966
+ onigBinding.HEAPU8.set(utfString.utf8Value, OnigString._sharedPtr);
4967
+ this.ptr = OnigString._sharedPtr;
4968
+ }
4969
+ else {
4970
+ this.ptr = utfString.createString(onigBinding);
4971
+ }
4972
+ }
4973
+ convertUtf8OffsetToUtf16(utf8Offset) {
4974
+ if (this.utf8OffsetToUtf16) {
4975
+ if (utf8Offset < 0)
4976
+ return 0;
4977
+ if (utf8Offset > this.utf8Length)
4978
+ return this.utf16Length;
4979
+ return this.utf8OffsetToUtf16[utf8Offset];
4980
+ }
4981
+ return utf8Offset;
4982
+ }
4983
+ convertUtf16OffsetToUtf8(utf16Offset) {
4984
+ if (this.utf16OffsetToUtf8) {
4985
+ if (utf16Offset < 0)
4986
+ return 0;
4987
+ if (utf16Offset > this.utf16Length)
4988
+ return this.utf8Length;
4989
+ return this.utf16OffsetToUtf8[utf16Offset];
4990
+ }
4991
+ return utf16Offset;
4992
+ }
4993
+ dispose() {
4994
+ if (this.ptr === OnigString._sharedPtr)
4995
+ OnigString._sharedPtrInUse = false;
4996
+ else
4997
+ this._onigBinding.ofree(this.ptr);
4998
+ }
4999
+ }
5000
+ class OnigScanner {
5001
+ _onigBinding;
5002
+ _ptr;
5003
+ constructor(patterns) {
5004
+ if (!onigBinding)
5005
+ throw new ShikiError('Must invoke loadWasm first.');
5006
+ const strPtrsArr = [];
5007
+ const strLenArr = [];
5008
+ for (let i = 0, len = patterns.length; i < len; i++) {
5009
+ const utfString = new UtfString(patterns[i]);
5010
+ strPtrsArr[i] = utfString.createString(onigBinding);
5011
+ strLenArr[i] = utfString.utf8Length;
5012
+ }
5013
+ const strPtrsPtr = onigBinding.omalloc(4 * patterns.length);
5014
+ onigBinding.HEAPU32.set(strPtrsArr, strPtrsPtr / 4);
5015
+ const strLenPtr = onigBinding.omalloc(4 * patterns.length);
5016
+ onigBinding.HEAPU32.set(strLenArr, strLenPtr / 4);
5017
+ const scannerPtr = onigBinding.createOnigScanner(strPtrsPtr, strLenPtr, patterns.length);
5018
+ for (let i = 0, len = patterns.length; i < len; i++)
5019
+ onigBinding.ofree(strPtrsArr[i]);
5020
+ onigBinding.ofree(strLenPtr);
5021
+ onigBinding.ofree(strPtrsPtr);
5022
+ if (scannerPtr === 0)
5023
+ throwLastOnigError(onigBinding);
5024
+ this._onigBinding = onigBinding;
5025
+ this._ptr = scannerPtr;
5026
+ }
5027
+ dispose() {
5028
+ this._onigBinding.freeOnigScanner(this._ptr);
5029
+ }
5030
+ findNextMatchSync(string, startPosition, arg) {
5031
+ // let debugCall = defaultDebugCall
5032
+ let options = 0 /* FindOption.None */;
5033
+ if (typeof arg === 'number') {
5034
+ // if (arg & FindOption.DebugCall)
5035
+ // debugCall = true
5036
+ options = arg;
5037
+ }
5038
+ if (typeof string === 'string') {
5039
+ string = new OnigString(string);
5040
+ const result = this._findNextMatchSync(string, startPosition, false, options);
5041
+ string.dispose();
5042
+ return result;
5043
+ }
5044
+ return this._findNextMatchSync(string, startPosition, false, options);
5045
+ }
5046
+ _findNextMatchSync(string, startPosition, debugCall, options) {
5047
+ const onigBinding = this._onigBinding;
5048
+ // let resultPtr: Pointer
5049
+ // if (debugCall)
5050
+ // resultPtr = onigBinding.findNextOnigScannerMatchDbg(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
5051
+ // else
5052
+ const resultPtr = onigBinding.findNextOnigScannerMatch(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options);
5053
+ if (resultPtr === 0) {
5054
+ // no match
5055
+ return null;
5056
+ }
5057
+ const HEAPU32 = onigBinding.HEAPU32;
5058
+ let offset = resultPtr / 4; // byte offset -> uint32 offset
5059
+ const index = HEAPU32[offset++];
5060
+ const count = HEAPU32[offset++];
5061
+ const captureIndices = [];
5062
+ for (let i = 0; i < count; i++) {
5063
+ const beg = string.convertUtf8OffsetToUtf16(HEAPU32[offset++]);
5064
+ const end = string.convertUtf8OffsetToUtf16(HEAPU32[offset++]);
5065
+ captureIndices[i] = {
5066
+ start: beg,
5067
+ end,
5068
+ length: end - beg,
5069
+ };
5070
+ }
5071
+ return {
5072
+ index,
5073
+ captureIndices,
5074
+ };
5075
+ }
5076
+ }
5077
+ function isInstantiatorOptionsObject(dataOrOptions) {
5078
+ return (typeof dataOrOptions.instantiator === 'function');
5079
+ }
5080
+ function isInstantiatorModule(dataOrOptions) {
5081
+ return (typeof dataOrOptions.default === 'function');
5082
+ }
5083
+ function isDataOptionsObject(dataOrOptions) {
5084
+ return (typeof dataOrOptions.data !== 'undefined');
5085
+ }
5086
+ function isResponse(dataOrOptions) {
5087
+ return (typeof Response !== 'undefined' && dataOrOptions instanceof Response);
5088
+ }
5089
+ function isArrayBuffer(data) {
5090
+ return (typeof ArrayBuffer !== 'undefined' && (data instanceof ArrayBuffer || ArrayBuffer.isView(data)))
5091
+ // eslint-disable-next-line node/prefer-global/buffer
5092
+ || (typeof Buffer !== 'undefined' && Buffer.isBuffer?.(data))
5093
+ || (typeof SharedArrayBuffer !== 'undefined' && data instanceof SharedArrayBuffer)
5094
+ || (typeof Uint32Array !== 'undefined' && data instanceof Uint32Array);
5095
+ }
5096
+ let initPromise;
5097
+ function loadWasm(options) {
5098
+ if (initPromise)
5099
+ return initPromise;
5100
+ async function _load() {
5101
+ onigBinding = await main(async (info) => {
5102
+ let instance = options;
5103
+ instance = await instance;
5104
+ if (typeof instance === 'function')
5105
+ instance = await instance(info);
5106
+ if (typeof instance === 'function')
5107
+ instance = await instance(info);
5108
+ if (isInstantiatorOptionsObject(instance)) {
5109
+ instance = await instance.instantiator(info);
5110
+ }
5111
+ else if (isInstantiatorModule(instance)) {
5112
+ instance = await instance.default(info);
5113
+ }
5114
+ else {
5115
+ if (isDataOptionsObject(instance))
5116
+ instance = instance.data;
5117
+ if (isResponse(instance)) {
5118
+ if (typeof WebAssembly.instantiateStreaming === 'function')
5119
+ instance = await _makeResponseStreamingLoader(instance)(info);
5120
+ else
5121
+ instance = await _makeResponseNonStreamingLoader(instance)(info);
5122
+ }
5123
+ else if (isArrayBuffer(instance)) {
5124
+ instance = await _makeArrayBufferLoader(instance)(info);
5125
+ }
5126
+ // import("shiki/onig.wasm") returns `{ default: WebAssembly.Module }` on cloudflare workers
5127
+ // https://developers.cloudflare.com/workers/wrangler/bundling/
5128
+ else if (instance instanceof WebAssembly.Module) {
5129
+ instance = await _makeArrayBufferLoader(instance)(info);
5130
+ }
5131
+ else if ('default' in instance && instance.default instanceof WebAssembly.Module) {
5132
+ instance = await _makeArrayBufferLoader(instance.default)(info);
5133
+ }
5134
+ }
5135
+ if ('instance' in instance)
5136
+ instance = instance.instance;
5137
+ if ('exports' in instance)
5138
+ instance = instance.exports;
5139
+ return instance;
5140
+ });
5141
+ }
5142
+ initPromise = _load();
5143
+ return initPromise;
5144
+ }
5145
+ function _makeArrayBufferLoader(data) {
5146
+ return importObject => WebAssembly.instantiate(data, importObject);
5147
+ }
5148
+ function _makeResponseStreamingLoader(data) {
5149
+ return importObject => WebAssembly.instantiateStreaming(data, importObject);
5150
+ }
5151
+ function _makeResponseNonStreamingLoader(data) {
5152
+ return async (importObject) => {
5153
+ const arrayBuffer = await data.arrayBuffer();
5154
+ return WebAssembly.instantiate(arrayBuffer, importObject);
5155
+ };
5156
+ }
5157
+ // export function createOnigString(str: string) {
5158
+ // return new OnigString(str)
5159
+ // }
5160
+ // export function createOnigScanner(patterns: string[]) {
5161
+ // return new OnigScanner(patterns)
5162
+ // }
5163
+ // export function setDefaultDebugCall(_defaultDebugCall: boolean): void {
5164
+ // defaultDebugCall = _defaultDebugCall
5165
+ // }
5166
+
5167
+ async function createWasmOnigEngine(options) {
5168
+ if (options)
5169
+ await loadWasm(options);
5170
+ return {
5171
+ createScanner(patterns) {
5172
+ return new OnigScanner(patterns);
5173
+ },
5174
+ createString(s) {
5175
+ return new OnigString(s);
5176
+ },
5177
+ };
5178
+ }
5179
+
5180
+ /**
5181
+ * https://github.com/microsoft/vscode/blob/f7f05dee53fb33fe023db2e06e30a89d3094488f/src/vs/platform/theme/common/colorRegistry.ts#L258-L268
5182
+ */
5183
+ const VSCODE_FALLBACK_EDITOR_FG = { light: '#333333', dark: '#bbbbbb' };
5184
+ const VSCODE_FALLBACK_EDITOR_BG = { light: '#fffffe', dark: '#1e1e1e' };
5185
+ const RESOLVED_KEY = '__shiki_resolved';
5186
+ /**
5187
+ * Normalize a textmate theme to shiki theme
5188
+ */
5189
+ function normalizeTheme(rawTheme) {
5190
+ // @ts-expect-error private field
5191
+ if (rawTheme?.[RESOLVED_KEY])
5192
+ return rawTheme;
5193
+ const theme = {
5194
+ ...rawTheme,
5195
+ };
5196
+ // Fallback settings
5197
+ if (theme.tokenColors && !theme.settings) {
5198
+ theme.settings = theme.tokenColors;
5199
+ delete theme.tokenColors;
5200
+ }
5201
+ theme.type ||= 'dark';
5202
+ theme.colorReplacements = { ...theme.colorReplacements };
5203
+ theme.settings ||= [];
5204
+ // Guess fg/bg colors
5205
+ let { bg, fg } = theme;
5206
+ if (!bg || !fg) {
5207
+ /**
5208
+ * First try:
5209
+ * Theme might contain a global `tokenColor` without `name` or `scope`
5210
+ * Used as default value for foreground/background
5211
+ */
5212
+ const globalSetting = theme.settings
5213
+ ? theme.settings.find((s) => !s.name && !s.scope)
5214
+ : undefined;
5215
+ if (globalSetting?.settings?.foreground)
5216
+ fg = globalSetting.settings.foreground;
5217
+ if (globalSetting?.settings?.background)
5218
+ bg = globalSetting.settings.background;
5219
+ /**
5220
+ * Second try:
5221
+ * If there's no global `tokenColor` without `name` or `scope`
5222
+ * Use `editor.foreground` and `editor.background`
5223
+ */
5224
+ if (!fg && theme?.colors?.['editor.foreground'])
5225
+ fg = theme.colors['editor.foreground'];
5226
+ if (!bg && theme?.colors?.['editor.background'])
5227
+ bg = theme.colors['editor.background'];
5228
+ /**
5229
+ * Last try:
5230
+ * If there's no fg/bg color specified in theme, use default
5231
+ */
5232
+ if (!fg)
5233
+ fg = theme.type === 'light' ? VSCODE_FALLBACK_EDITOR_FG.light : VSCODE_FALLBACK_EDITOR_FG.dark;
5234
+ if (!bg)
5235
+ bg = theme.type === 'light' ? VSCODE_FALLBACK_EDITOR_BG.light : VSCODE_FALLBACK_EDITOR_BG.dark;
5236
+ theme.fg = fg;
5237
+ theme.bg = bg;
5238
+ }
5239
+ // Push a no-scope setting with fallback colors
5240
+ if (!(theme.settings[0] && theme.settings[0].settings && !theme.settings[0].scope)) {
5241
+ theme.settings.unshift({
5242
+ settings: {
5243
+ foreground: theme.fg,
5244
+ background: theme.bg,
5245
+ },
5246
+ });
5247
+ }
5248
+ // Push non-hex colors to color replacements, as `vscode-textmate` doesn't support them
5249
+ let replacementCount = 0;
5250
+ const replacementMap = new Map();
5251
+ function getReplacementColor(value) {
5252
+ if (replacementMap.has(value))
5253
+ return replacementMap.get(value);
5254
+ replacementCount += 1;
5255
+ const hex = `#${replacementCount.toString(16).padStart(8, '0').toLowerCase()}`;
5256
+ if (theme.colorReplacements?.[`#${hex}`]) // already exists
5257
+ return getReplacementColor(value);
5258
+ replacementMap.set(value, hex);
5259
+ return hex;
5248
5260
  }
5249
- }
5250
- class OnigString {
5251
- static LAST_ID = 0;
5252
- static _sharedPtr = 0; // a pointer to a string of 10000 bytes
5253
- static _sharedPtrInUse = false;
5254
- id = (++OnigString.LAST_ID);
5255
- _onigBinding;
5256
- content;
5257
- utf16Length;
5258
- utf8Length;
5259
- utf16OffsetToUtf8;
5260
- utf8OffsetToUtf16;
5261
- ptr;
5262
- constructor(str) {
5263
- if (!onigBinding)
5264
- throw new ShikiError('Must invoke loadWasm first.');
5265
- this._onigBinding = onigBinding;
5266
- this.content = str;
5267
- const utfString = new UtfString(str);
5268
- this.utf16Length = utfString.utf16Length;
5269
- this.utf8Length = utfString.utf8Length;
5270
- this.utf16OffsetToUtf8 = utfString.utf16OffsetToUtf8;
5271
- this.utf8OffsetToUtf16 = utfString.utf8OffsetToUtf16;
5272
- if (this.utf8Length < 10000 && !OnigString._sharedPtrInUse) {
5273
- if (!OnigString._sharedPtr)
5274
- OnigString._sharedPtr = onigBinding.omalloc(10000);
5275
- OnigString._sharedPtrInUse = true;
5276
- onigBinding.HEAPU8.set(utfString.utf8Value, OnigString._sharedPtr);
5277
- this.ptr = OnigString._sharedPtr;
5261
+ theme.settings = theme.settings.map((setting) => {
5262
+ const replaceFg = setting.settings?.foreground && !setting.settings.foreground.startsWith('#');
5263
+ const replaceBg = setting.settings?.background && !setting.settings.background.startsWith('#');
5264
+ if (!replaceFg && !replaceBg)
5265
+ return setting;
5266
+ const clone = {
5267
+ ...setting,
5268
+ settings: {
5269
+ ...setting.settings,
5270
+ },
5271
+ };
5272
+ if (replaceFg) {
5273
+ const replacement = getReplacementColor(setting.settings.foreground);
5274
+ theme.colorReplacements[replacement] = setting.settings.foreground;
5275
+ clone.settings.foreground = replacement;
5278
5276
  }
5279
- else {
5280
- this.ptr = utfString.createString(onigBinding);
5277
+ if (replaceBg) {
5278
+ const replacement = getReplacementColor(setting.settings.background);
5279
+ theme.colorReplacements[replacement] = setting.settings.background;
5280
+ clone.settings.background = replacement;
5281
+ }
5282
+ return clone;
5283
+ });
5284
+ for (const key of Object.keys(theme.colors || {})) {
5285
+ // Only patch for known keys
5286
+ if (key === 'editor.foreground' || key === 'editor.background' || key.startsWith('terminal.ansi')) {
5287
+ if (!theme.colors[key]?.startsWith('#')) {
5288
+ const replacement = getReplacementColor(theme.colors[key]);
5289
+ theme.colorReplacements[replacement] = theme.colors[key];
5290
+ theme.colors[key] = replacement;
5291
+ }
5281
5292
  }
5282
5293
  }
5283
- convertUtf8OffsetToUtf16(utf8Offset) {
5284
- if (this.utf8OffsetToUtf16) {
5285
- if (utf8Offset < 0)
5286
- return 0;
5287
- if (utf8Offset > this.utf8Length)
5288
- return this.utf16Length;
5289
- return this.utf8OffsetToUtf16[utf8Offset];
5294
+ Object.defineProperty(theme, RESOLVED_KEY, {
5295
+ enumerable: false,
5296
+ writable: false,
5297
+ value: true,
5298
+ });
5299
+ return theme;
5300
+ }
5301
+
5302
+ /**
5303
+ * Resolve
5304
+ */
5305
+ async function resolveLangs(langs) {
5306
+ return Array.from(new Set((await Promise.all(langs
5307
+ .filter(l => !isSpecialLang(l))
5308
+ .map(async (lang) => await normalizeGetter(lang).then(r => Array.isArray(r) ? r : [r])))).flat()));
5309
+ }
5310
+ async function resolveThemes(themes) {
5311
+ const resolved = await Promise.all(themes.map(async (theme) => isSpecialTheme(theme)
5312
+ ? null
5313
+ : normalizeTheme(await normalizeGetter(theme))));
5314
+ return resolved.filter(i => !!i);
5315
+ }
5316
+
5317
+ class Registry extends Registry$1 {
5318
+ _resolver;
5319
+ _themes;
5320
+ _langs;
5321
+ _alias;
5322
+ _resolvedThemes = new Map();
5323
+ _resolvedGrammars = new Map();
5324
+ _langMap = new Map();
5325
+ _langGraph = new Map();
5326
+ _textmateThemeCache = new WeakMap();
5327
+ _loadedThemesCache = null;
5328
+ _loadedLanguagesCache = null;
5329
+ constructor(_resolver, _themes, _langs, _alias = {}) {
5330
+ super(_resolver);
5331
+ this._resolver = _resolver;
5332
+ this._themes = _themes;
5333
+ this._langs = _langs;
5334
+ this._alias = _alias;
5335
+ this._themes.map(t => this.loadTheme(t));
5336
+ this.loadLanguages(this._langs);
5337
+ }
5338
+ getTheme(theme) {
5339
+ if (typeof theme === 'string')
5340
+ return this._resolvedThemes.get(theme);
5341
+ else
5342
+ return this.loadTheme(theme);
5343
+ }
5344
+ loadTheme(theme) {
5345
+ const _theme = normalizeTheme(theme);
5346
+ if (_theme.name) {
5347
+ this._resolvedThemes.set(_theme.name, _theme);
5348
+ // Reset cache
5349
+ this._loadedThemesCache = null;
5290
5350
  }
5291
- return utf8Offset;
5351
+ return _theme;
5292
5352
  }
5293
- convertUtf16OffsetToUtf8(utf16Offset) {
5294
- if (this.utf16OffsetToUtf8) {
5295
- if (utf16Offset < 0)
5296
- return 0;
5297
- if (utf16Offset > this.utf16Length)
5298
- return this.utf8Length;
5299
- return this.utf16OffsetToUtf8[utf16Offset];
5353
+ getLoadedThemes() {
5354
+ if (!this._loadedThemesCache)
5355
+ this._loadedThemesCache = [...this._resolvedThemes.keys()];
5356
+ return this._loadedThemesCache;
5357
+ }
5358
+ // Override and re-implement this method to cache the textmate themes as `TextMateTheme.createFromRawTheme`
5359
+ // is expensive. Themes can switch often especially for dual-theme support.
5360
+ //
5361
+ // The parent class also accepts `colorMap` as the second parameter, but since we don't use that,
5362
+ // we omit here so it's easier to cache the themes.
5363
+ setTheme(theme) {
5364
+ let textmateTheme = this._textmateThemeCache.get(theme);
5365
+ if (!textmateTheme) {
5366
+ textmateTheme = Theme.createFromRawTheme(theme);
5367
+ this._textmateThemeCache.set(theme, textmateTheme);
5300
5368
  }
5301
- return utf16Offset;
5369
+ // @ts-expect-error Access private `_syncRegistry`, but should work in runtime
5370
+ this._syncRegistry.setTheme(textmateTheme);
5302
5371
  }
5303
- dispose() {
5304
- if (this.ptr === OnigString._sharedPtr)
5305
- OnigString._sharedPtrInUse = false;
5306
- else
5307
- this._onigBinding.ofree(this.ptr);
5372
+ getGrammar(name) {
5373
+ if (this._alias[name]) {
5374
+ const resolved = new Set([name]);
5375
+ while (this._alias[name]) {
5376
+ name = this._alias[name];
5377
+ if (resolved.has(name))
5378
+ throw new ShikiError(`Circular alias \`${Array.from(resolved).join(' -> ')} -> ${name}\``);
5379
+ resolved.add(name);
5380
+ }
5381
+ }
5382
+ return this._resolvedGrammars.get(name);
5308
5383
  }
5309
- }
5310
- class OnigScanner {
5311
- _onigBinding;
5312
- _ptr;
5313
- constructor(patterns) {
5314
- if (!onigBinding)
5315
- throw new ShikiError('Must invoke loadWasm first.');
5316
- const strPtrsArr = [];
5317
- const strLenArr = [];
5318
- for (let i = 0, len = patterns.length; i < len; i++) {
5319
- const utfString = new UtfString(patterns[i]);
5320
- strPtrsArr[i] = utfString.createString(onigBinding);
5321
- strLenArr[i] = utfString.utf8Length;
5384
+ loadLanguage(lang) {
5385
+ if (this.getGrammar(lang.name))
5386
+ return;
5387
+ const embeddedLazilyBy = new Set([...this._langMap.values()]
5388
+ .filter(i => i.embeddedLangsLazy?.includes(lang.name)));
5389
+ this._resolver.addLanguage(lang);
5390
+ const grammarConfig = {
5391
+ balancedBracketSelectors: lang.balancedBracketSelectors || ['*'],
5392
+ unbalancedBracketSelectors: lang.unbalancedBracketSelectors || [],
5393
+ };
5394
+ // @ts-expect-error Private members, set this to override the previous grammar (that can be a stub)
5395
+ this._syncRegistry._rawGrammars.set(lang.scopeName, lang);
5396
+ const g = this.loadGrammarWithConfiguration(lang.scopeName, 1, grammarConfig);
5397
+ g.name = lang.name;
5398
+ this._resolvedGrammars.set(lang.name, g);
5399
+ if (lang.aliases) {
5400
+ lang.aliases.forEach((alias) => {
5401
+ this._alias[alias] = lang.name;
5402
+ });
5403
+ }
5404
+ // Reset cache
5405
+ this._loadedLanguagesCache = null;
5406
+ // If there is a language that embeds this language lazily, we need to reload it
5407
+ if (embeddedLazilyBy.size) {
5408
+ for (const e of embeddedLazilyBy) {
5409
+ this._resolvedGrammars.delete(e.name);
5410
+ // Reset cache
5411
+ this._loadedLanguagesCache = null;
5412
+ // @ts-expect-error clear cache
5413
+ this._syncRegistry?._injectionGrammars?.delete(e.scopeName);
5414
+ // @ts-expect-error clear cache
5415
+ this._syncRegistry?._grammars?.delete(e.scopeName);
5416
+ this.loadLanguage(this._langMap.get(e.name));
5417
+ }
5322
5418
  }
5323
- const strPtrsPtr = onigBinding.omalloc(4 * patterns.length);
5324
- onigBinding.HEAPU32.set(strPtrsArr, strPtrsPtr / 4);
5325
- const strLenPtr = onigBinding.omalloc(4 * patterns.length);
5326
- onigBinding.HEAPU32.set(strLenArr, strLenPtr / 4);
5327
- const scannerPtr = onigBinding.createOnigScanner(strPtrsPtr, strLenPtr, patterns.length);
5328
- for (let i = 0, len = patterns.length; i < len; i++)
5329
- onigBinding.ofree(strPtrsArr[i]);
5330
- onigBinding.ofree(strLenPtr);
5331
- onigBinding.ofree(strPtrsPtr);
5332
- if (scannerPtr === 0)
5333
- throwLastOnigError(onigBinding);
5334
- this._onigBinding = onigBinding;
5335
- this._ptr = scannerPtr;
5336
5419
  }
5337
5420
  dispose() {
5338
- this._onigBinding.freeOnigScanner(this._ptr);
5421
+ super.dispose();
5422
+ this._resolvedThemes.clear();
5423
+ this._resolvedGrammars.clear();
5424
+ this._langMap.clear();
5425
+ this._langGraph.clear();
5426
+ this._loadedThemesCache = null;
5339
5427
  }
5340
- findNextMatchSync(string, startPosition, arg) {
5341
- // let debugCall = defaultDebugCall
5342
- let options = 0 /* FindOption.None */;
5343
- if (typeof arg === 'number') {
5344
- // if (arg & FindOption.DebugCall)
5345
- // debugCall = true
5346
- options = arg;
5347
- }
5348
- if (typeof string === 'string') {
5349
- string = new OnigString(string);
5350
- const result = this._findNextMatchSync(string, startPosition, false, options);
5351
- string.dispose();
5352
- return result;
5428
+ loadLanguages(langs) {
5429
+ for (const lang of langs)
5430
+ this.resolveEmbeddedLanguages(lang);
5431
+ const langsGraphArray = Array.from(this._langGraph.entries());
5432
+ const missingLangs = langsGraphArray.filter(([_, lang]) => !lang);
5433
+ if (missingLangs.length) {
5434
+ const dependents = langsGraphArray
5435
+ .filter(([_, lang]) => lang && lang.embeddedLangs?.some(l => missingLangs.map(([name]) => name).includes(l)))
5436
+ .filter(lang => !missingLangs.includes(lang));
5437
+ throw new ShikiError(`Missing languages ${missingLangs.map(([name]) => `\`${name}\``).join(', ')}, required by ${dependents.map(([name]) => `\`${name}\``).join(', ')}`);
5353
5438
  }
5354
- return this._findNextMatchSync(string, startPosition, false, options);
5439
+ for (const [_, lang] of langsGraphArray)
5440
+ this._resolver.addLanguage(lang);
5441
+ for (const [_, lang] of langsGraphArray)
5442
+ this.loadLanguage(lang);
5355
5443
  }
5356
- _findNextMatchSync(string, startPosition, debugCall, options) {
5357
- const onigBinding = this._onigBinding;
5358
- // let resultPtr: Pointer
5359
- // if (debugCall)
5360
- // resultPtr = onigBinding.findNextOnigScannerMatchDbg(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options)
5361
- // else
5362
- const resultPtr = onigBinding.findNextOnigScannerMatch(this._ptr, string.id, string.ptr, string.utf8Length, string.convertUtf16OffsetToUtf8(startPosition), options);
5363
- if (resultPtr === 0) {
5364
- // no match
5365
- return null;
5366
- }
5367
- const HEAPU32 = onigBinding.HEAPU32;
5368
- let offset = resultPtr / 4; // byte offset -> uint32 offset
5369
- const index = HEAPU32[offset++];
5370
- const count = HEAPU32[offset++];
5371
- const captureIndices = [];
5372
- for (let i = 0; i < count; i++) {
5373
- const beg = string.convertUtf8OffsetToUtf16(HEAPU32[offset++]);
5374
- const end = string.convertUtf8OffsetToUtf16(HEAPU32[offset++]);
5375
- captureIndices[i] = {
5376
- start: beg,
5377
- end,
5378
- length: end - beg,
5379
- };
5444
+ getLoadedLanguages() {
5445
+ if (!this._loadedLanguagesCache) {
5446
+ this._loadedLanguagesCache = [
5447
+ ...new Set([...this._resolvedGrammars.keys(), ...Object.keys(this._alias)]),
5448
+ ];
5380
5449
  }
5381
- return {
5382
- index,
5383
- captureIndices,
5384
- };
5450
+ return this._loadedLanguagesCache;
5385
5451
  }
5386
- }
5387
- function isInstantiatorOptionsObject(dataOrOptions) {
5388
- return (typeof dataOrOptions.instantiator === 'function');
5389
- }
5390
- function isInstantiatorModule(dataOrOptions) {
5391
- return (typeof dataOrOptions.default === 'function');
5392
- }
5393
- function isDataOptionsObject(dataOrOptions) {
5394
- return (typeof dataOrOptions.data !== 'undefined');
5395
- }
5396
- function isResponse(dataOrOptions) {
5397
- return (typeof Response !== 'undefined' && dataOrOptions instanceof Response);
5398
- }
5399
- function isArrayBuffer(data) {
5400
- return (typeof ArrayBuffer !== 'undefined' && (data instanceof ArrayBuffer || ArrayBuffer.isView(data)))
5401
- // eslint-disable-next-line node/prefer-global/buffer
5402
- || (typeof Buffer !== 'undefined' && Buffer.isBuffer?.(data))
5403
- || (typeof SharedArrayBuffer !== 'undefined' && data instanceof SharedArrayBuffer)
5404
- || (typeof Uint32Array !== 'undefined' && data instanceof Uint32Array);
5405
- }
5406
- let initPromise;
5407
- function loadWasm(options) {
5408
- if (initPromise)
5409
- return initPromise;
5410
- async function _load() {
5411
- onigBinding = await main(async (info) => {
5412
- let instance = options;
5413
- instance = await instance;
5414
- if (typeof instance === 'function')
5415
- instance = await instance(info);
5416
- if (typeof instance === 'function')
5417
- instance = await instance(info);
5418
- if (isInstantiatorOptionsObject(instance)) {
5419
- instance = await instance.instantiator(info);
5420
- }
5421
- else if (isInstantiatorModule(instance)) {
5422
- instance = await instance.default(info);
5423
- }
5424
- else {
5425
- if (isDataOptionsObject(instance))
5426
- instance = instance.data;
5427
- if (isResponse(instance)) {
5428
- if (typeof WebAssembly.instantiateStreaming === 'function')
5429
- instance = await _makeResponseStreamingLoader(instance)(info);
5430
- else
5431
- instance = await _makeResponseNonStreamingLoader(instance)(info);
5432
- }
5433
- else if (isArrayBuffer(instance)) {
5434
- instance = await _makeArrayBufferLoader(instance)(info);
5435
- }
5436
- // import("shiki/onig.wasm") returns `{ default: WebAssembly.Module }` on cloudflare workers
5437
- // https://developers.cloudflare.com/workers/wrangler/bundling/
5438
- else if (instance instanceof WebAssembly.Module) {
5439
- instance = await _makeArrayBufferLoader(instance)(info);
5440
- }
5441
- else if ('default' in instance && instance.default instanceof WebAssembly.Module) {
5442
- instance = await _makeArrayBufferLoader(instance.default)(info);
5443
- }
5444
- }
5445
- if ('instance' in instance)
5446
- instance = instance.instance;
5447
- if ('exports' in instance)
5448
- instance = instance.exports;
5449
- return instance;
5450
- });
5452
+ resolveEmbeddedLanguages(lang) {
5453
+ this._langMap.set(lang.name, lang);
5454
+ this._langGraph.set(lang.name, lang);
5455
+ if (lang.embeddedLangs) {
5456
+ for (const embeddedLang of lang.embeddedLangs)
5457
+ this._langGraph.set(embeddedLang, this._langMap.get(embeddedLang));
5458
+ }
5451
5459
  }
5452
- initPromise = _load();
5453
- return initPromise;
5454
- }
5455
- function _makeArrayBufferLoader(data) {
5456
- return importObject => WebAssembly.instantiate(data, importObject);
5457
- }
5458
- function _makeResponseStreamingLoader(data) {
5459
- return importObject => WebAssembly.instantiateStreaming(data, importObject);
5460
- }
5461
- function _makeResponseNonStreamingLoader(data) {
5462
- return async (importObject) => {
5463
- const arrayBuffer = await data.arrayBuffer();
5464
- return WebAssembly.instantiate(arrayBuffer, importObject);
5465
- };
5466
5460
  }
5467
- // export function createOnigString(str: string) {
5468
- // return new OnigString(str)
5469
- // }
5470
- // export function createOnigScanner(patterns: string[]) {
5471
- // return new OnigScanner(patterns)
5472
- // }
5473
- // export function setDefaultDebugCall(_defaultDebugCall: boolean): void {
5474
- // defaultDebugCall = _defaultDebugCall
5475
- // }
5476
5461
 
5477
- async function createWasmOnigEngine(options) {
5478
- if (options)
5479
- await loadWasm(options);
5480
- return {
5481
- createScanner(patterns) {
5482
- return new OnigScanner(patterns);
5483
- },
5484
- createString(s) {
5485
- return new OnigString(s);
5486
- },
5487
- };
5462
+ class Resolver {
5463
+ _langs = new Map();
5464
+ _scopeToLang = new Map();
5465
+ _injections = new Map();
5466
+ _onigLib;
5467
+ constructor(engine, langs) {
5468
+ this._onigLib = {
5469
+ createOnigScanner: patterns => engine.createScanner(patterns),
5470
+ createOnigString: s => engine.createString(s),
5471
+ };
5472
+ langs.forEach(i => this.addLanguage(i));
5473
+ }
5474
+ get onigLib() {
5475
+ return this._onigLib;
5476
+ }
5477
+ getLangRegistration(langIdOrAlias) {
5478
+ return this._langs.get(langIdOrAlias);
5479
+ }
5480
+ loadGrammar(scopeName) {
5481
+ return this._scopeToLang.get(scopeName);
5482
+ }
5483
+ addLanguage(l) {
5484
+ this._langs.set(l.name, l);
5485
+ if (l.aliases) {
5486
+ l.aliases.forEach((a) => {
5487
+ this._langs.set(a, l);
5488
+ });
5489
+ }
5490
+ this._scopeToLang.set(l.scopeName, l);
5491
+ if (l.injectTo) {
5492
+ l.injectTo.forEach((i) => {
5493
+ if (!this._injections.get(i))
5494
+ this._injections.set(i, []);
5495
+ this._injections.get(i).push(l.scopeName);
5496
+ });
5497
+ }
5498
+ }
5499
+ getInjections(scopeName) {
5500
+ const scopeParts = scopeName.split('.');
5501
+ let injections = [];
5502
+ for (let i = 1; i <= scopeParts.length; i++) {
5503
+ const subScopeName = scopeParts.slice(0, i).join('.');
5504
+ injections = [...injections, ...(this._injections.get(subScopeName) || [])];
5505
+ }
5506
+ return injections;
5507
+ }
5488
5508
  }
5489
5509
 
5490
- let _defaultWasmLoader;
5491
- /**
5492
- * Set the default wasm loader for `loadWasm`.
5493
- * @internal
5494
- */
5495
- function setDefaultWasmLoader(_loader) {
5496
- _defaultWasmLoader = _loader;
5497
- }
5498
5510
  let instancesCount = 0;
5499
5511
  /**
5500
5512
  * Get the minimal shiki context for rendering.
5513
+ *
5514
+ * Synchronous version of `createShikiInternal`, which requires to provide the engine and all themes and languages upfront.
5501
5515
  */
5502
- async function createShikiInternal(options = {}) {
5516
+ function createShikiInternalSync(options) {
5503
5517
  instancesCount += 1;
5504
5518
  if (options.warnings !== false && instancesCount >= 10 && instancesCount % 10 === 0)
5505
5519
  console.warn(`[Shiki] ${instancesCount} instances have been created. Shiki is supposed to be used as a singleton, consider refactoring your code to cache your highlighter instance; Or call \`highlighter.dispose()\` to release unused instances.`);
5506
5520
  let isDisposed = false;
5507
- async function normalizeGetter(p) {
5508
- return Promise.resolve(typeof p === 'function' ? p() : p).then(r => r.default || r);
5509
- }
5510
- async function resolveLangs(langs) {
5511
- return Array.from(new Set((await Promise.all(langs
5512
- .filter(l => !isSpecialLang(l))
5513
- .map(async (lang) => await normalizeGetter(lang).then(r => Array.isArray(r) ? r : [r])))).flat()));
5514
- }
5515
- const [themes, langs,] = await Promise.all([
5516
- Promise.all((options.themes || []).map(normalizeGetter)).then(r => r.map(normalizeTheme)),
5517
- resolveLangs(options.langs || []),
5518
- ]);
5519
- const resolver = new Resolver(Promise.resolve(options.engine || createWasmOnigEngine(options.loadWasm || _defaultWasmLoader)), langs);
5521
+ if (!options.engine)
5522
+ throw new ShikiError('`engine` option is required for synchronous mode');
5523
+ const langs = (options.langs || []).flat(1);
5524
+ const themes = (options.themes || []).flat(1).map(normalizeTheme);
5525
+ const resolver = new Resolver(options.engine, langs);
5520
5526
  const _registry = new Registry(resolver, themes, langs, options.langAlias);
5521
- await _registry.init();
5522
5527
  let _lastTheme;
5523
5528
  function getLanguage(name) {
5524
5529
  ensureNotDisposed();
@@ -5557,15 +5562,22 @@ async function createShikiInternal(options = {}) {
5557
5562
  ensureNotDisposed();
5558
5563
  return _registry.getLoadedLanguages();
5559
5564
  }
5565
+ function loadLanguageSync(...langs) {
5566
+ ensureNotDisposed();
5567
+ _registry.loadLanguages(langs.flat(1));
5568
+ }
5560
5569
  async function loadLanguage(...langs) {
5570
+ return loadLanguageSync(await resolveLangs(langs));
5571
+ }
5572
+ async function loadThemeSync(...themes) {
5561
5573
  ensureNotDisposed();
5562
- await _registry.loadLanguages(await resolveLangs(langs));
5574
+ for (const theme of themes.flat(1)) {
5575
+ _registry.loadTheme(theme);
5576
+ }
5563
5577
  }
5564
5578
  async function loadTheme(...themes) {
5565
5579
  ensureNotDisposed();
5566
- await Promise.all(themes.map(async (theme) => isSpecialTheme(theme)
5567
- ? null
5568
- : _registry.loadTheme(await normalizeGetter(theme))));
5580
+ return loadThemeSync(await resolveThemes(themes));
5569
5581
  }
5570
5582
  function ensureNotDisposed() {
5571
5583
  if (isDisposed)
@@ -5585,11 +5597,39 @@ async function createShikiInternal(options = {}) {
5585
5597
  getLoadedThemes,
5586
5598
  getLoadedLanguages,
5587
5599
  loadLanguage,
5600
+ loadLanguageSync,
5588
5601
  loadTheme,
5602
+ loadThemeSync,
5589
5603
  dispose,
5590
5604
  [Symbol.dispose]: dispose,
5591
5605
  };
5592
5606
  }
5607
+
5608
+ let _defaultWasmLoader;
5609
+ /**
5610
+ * Set the default wasm loader for `loadWasm`.
5611
+ * @internal
5612
+ */
5613
+ function setDefaultWasmLoader(_loader) {
5614
+ _defaultWasmLoader = _loader;
5615
+ }
5616
+ /**
5617
+ * Get the minimal shiki context for rendering.
5618
+ */
5619
+ async function createShikiInternal(options = {}) {
5620
+ const [themes, langs, engine,] = await Promise.all([
5621
+ resolveThemes(options.themes || []),
5622
+ resolveLangs(options.langs || []),
5623
+ (options.engine || createWasmOnigEngine(options.loadWasm || _defaultWasmLoader)),
5624
+ ]);
5625
+ return createShikiInternalSync({
5626
+ ...options,
5627
+ loadWasm: undefined,
5628
+ themes,
5629
+ langs,
5630
+ engine,
5631
+ });
5632
+ }
5593
5633
  /**
5594
5634
  * @deprecated Use `createShikiInternal` instead.
5595
5635
  */
@@ -5602,7 +5642,7 @@ function getShikiInternal(options = {}) {
5602
5642
  * Create a Shiki core highlighter instance, with no languages or themes bundled.
5603
5643
  * Wasm and each language and theme must be loaded manually.
5604
5644
  *
5605
- * @see http://shiki.style/guide/install#fine-grained-bundle
5645
+ * @see http://shiki.style/guide/bundles#fine-grained-bundle
5606
5646
  */
5607
5647
  async function createHighlighterCore(options = {}) {
5608
5648
  const internal = await createShikiInternal(options);
@@ -5617,6 +5657,27 @@ async function createHighlighterCore(options = {}) {
5617
5657
  getInternalContext: () => internal,
5618
5658
  };
5619
5659
  }
5660
+ /**
5661
+ * Create a Shiki core highlighter instance, with no languages or themes bundled.
5662
+ * Wasm and each language and theme must be loaded manually.
5663
+ *
5664
+ * Synchronous version of `createHighlighterCore`, which requires to provide the engine and all themes and languages upfront.
5665
+ *
5666
+ * @see http://shiki.style/guide/bundles#fine-grained-bundle
5667
+ */
5668
+ function createHighlighterCoreSync(options = {}) {
5669
+ const internal = createShikiInternalSync(options);
5670
+ return {
5671
+ getLastGrammarState: (code, options) => getLastGrammarState(internal, code, options),
5672
+ codeToTokensBase: (code, options) => codeToTokensBase(internal, code, options),
5673
+ codeToTokensWithThemes: (code, options) => codeToTokensWithThemes(internal, code, options),
5674
+ codeToTokens: (code, options) => codeToTokens(internal, code, options),
5675
+ codeToHast: (code, options) => codeToHast(internal, code, options),
5676
+ codeToHtml: (code, options) => codeToHtml(internal, code, options),
5677
+ ...internal,
5678
+ getInternalContext: () => internal,
5679
+ };
5680
+ }
5620
5681
  function makeSingletonHighlighterCore(createHighlighter) {
5621
5682
  let _shiki;
5622
5683
  async function getSingletonHighlighterCore(options = {}) {
@@ -5649,14 +5710,23 @@ function getHighlighterCore(options = {}) {
5649
5710
  return createHighlighterCore(options);
5650
5711
  }
5651
5712
 
5652
- /**
5653
- * Create a `createHighlighter` function with bundled themes and languages.
5654
- *
5655
- * @param bundledLanguages
5656
- * @param bundledThemes
5657
- * @param loadWasm
5658
- */
5659
- function createdBundledHighlighter(bundledLanguages, bundledThemes, loadWasm) {
5713
+ // Implementation
5714
+ function createdBundledHighlighter(arg1, arg2, arg3) {
5715
+ let bundledLanguages;
5716
+ let bundledThemes;
5717
+ let engine;
5718
+ if (arg2) {
5719
+ // TODO: next: console.warn('`createdBundledHighlighter` signature with `bundledLanguages` and `bundledThemes` is deprecated. Use the options object signature instead.')
5720
+ bundledLanguages = arg1;
5721
+ bundledThemes = arg2;
5722
+ engine = () => createWasmOnigEngine(arg3);
5723
+ }
5724
+ else {
5725
+ const options = arg1;
5726
+ bundledLanguages = options.langs;
5727
+ bundledThemes = options.themes;
5728
+ engine = options.engine;
5729
+ }
5660
5730
  async function createHighlighter(options) {
5661
5731
  function resolveLang(lang) {
5662
5732
  if (typeof lang === 'string') {
@@ -5684,10 +5754,10 @@ function createdBundledHighlighter(bundledLanguages, bundledThemes, loadWasm) {
5684
5754
  const langs = (options.langs ?? [])
5685
5755
  .map(i => resolveLang(i));
5686
5756
  const core = await createHighlighterCore({
5757
+ engine: engine(),
5687
5758
  ...options,
5688
5759
  themes: _themes,
5689
5760
  langs,
5690
- loadWasm,
5691
5761
  });
5692
5762
  return {
5693
5763
  ...core,
@@ -5813,7 +5883,8 @@ function syntaxLowering(input, options = {}) {
5813
5883
  const {
5814
5884
  preserveFlags = false,
5815
5885
  removePossessiveQuantifier = false,
5816
- removeAtomicGroup = false
5886
+ removeAtomicGroup = false,
5887
+ convertHexDigitsShorthand = false
5817
5888
  } = options;
5818
5889
  let output = "";
5819
5890
  const flags = /* @__PURE__ */ new Set();
@@ -5830,14 +5901,29 @@ function syntaxLowering(input, options = {}) {
5830
5901
  const head = stack[0];
5831
5902
  const wsEscape = freeSpacingGlobal || freeSpacingLocal.length;
5832
5903
  if (char === "\\") {
5833
- if (input[i + 1] === "h") {
5834
- if (head === "[") {
5835
- output += " \\t";
5836
- } else {
5837
- output += "[ \\t]";
5904
+ if (convertHexDigitsShorthand) {
5905
+ if (input[i + 1] === "h") {
5906
+ const body = `0-9A-Fa-f`;
5907
+ if (head === "[") {
5908
+ output += body;
5909
+ } else {
5910
+ output += `[${body}]`;
5911
+ }
5912
+ i += 2;
5913
+ continue;
5914
+ }
5915
+ if (input[i + 1] === "H") {
5916
+ if (head === "[") {
5917
+ throw new RegExpConversionError(
5918
+ "Expending \\H in character class is not supported",
5919
+ { pattern: input, converted: output, cursor: i }
5920
+ );
5921
+ } else {
5922
+ output += `[^0-9A-Fa-f]`;
5923
+ }
5924
+ i += 2;
5925
+ continue;
5838
5926
  }
5839
- i += 2;
5840
- continue;
5841
5927
  }
5842
5928
  output += char + input[i + 1];
5843
5929
  i += 2;
@@ -6068,6 +6154,7 @@ function onigurumaToRegexp(pattern, options = {}) {
6068
6154
  } = syntaxLowering(pattern, {
6069
6155
  removePossessiveQuantifier: true,
6070
6156
  removeAtomicGroup: true,
6157
+ convertHexDigitsShorthand: true,
6071
6158
  ...options
6072
6159
  });
6073
6160
  return construct(converted, {
@@ -6199,4 +6286,4 @@ function createJavaScriptRegexEngine(options = {}) {
6199
6286
  };
6200
6287
  }
6201
6288
 
6202
- export { FontStyle, ShikiError, addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createHighlighterCore, createJavaScriptRegexEngine, createPositionConverter, createShikiInternal, createSingletonShorthands, createWasmOnigEngine, createdBundledHighlighter, getHighlighterCore, getShikiInternal, getSingletonHighlighterCore, getTokenStyleObject, toHtml as hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, loadWasm, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeTheme, resolveColorReplacements, setDefaultWasmLoader, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations };
6289
+ export { FontStyle, ShikiError, addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createHighlighterCore, createHighlighterCoreSync, createJavaScriptRegexEngine, createPositionConverter, createShikiInternal, createShikiInternalSync, createSingletonShorthands, createWasmOnigEngine, createdBundledHighlighter, getHighlighterCore, getShikiInternal, getSingletonHighlighterCore, getTokenStyleObject, toHtml as hastToHtml, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, loadWasm, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, setDefaultWasmLoader, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations };