import { ShikiError as ShikiError$1 } from '@shikijs/types'; export * from '@shikijs/types'; import { createOnigurumaEngine as createOnigurumaEngine$1, loadWasm as loadWasm$1, getDefaultWasmLoader } from '@shikijs/engine-oniguruma'; import { w as warnDeprecated } from './shared/core.Bn_XU0Iv.mjs'; export { e as enableDeprecationWarnings } from './shared/core.Bn_XU0Iv.mjs'; import { FontStyle, INITIAL, EncodedTokenMetadata, Registry as Registry$1, Theme } from '@shikijs/vscode-textmate'; export { FontStyle, EncodedTokenMetadata as StackElementMetadata } from '@shikijs/vscode-textmate'; import { toHtml } from 'hast-util-to-html'; export { toHtml as hastToHtml } from 'hast-util-to-html'; import { createJavaScriptRegexEngine as createJavaScriptRegexEngine$1, defaultJavaScriptRegexConstructor as defaultJavaScriptRegexConstructor$1 } from '@shikijs/engine-javascript'; function createOnigurumaEngine(options) { warnDeprecated("import `createOnigurumaEngine` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead"); return createOnigurumaEngine$1(options); } function createWasmOnigEngine(options) { warnDeprecated("import `createOnigurumaEngine` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead"); return createOnigurumaEngine$1(options); } function loadWasm(options) { warnDeprecated("import `loadWasm` from `@shikijs/engine-oniguruma` or `shiki/engine/oniguruma` instead"); return loadWasm$1(options); } function toArray(x) { return Array.isArray(x) ? x : [x]; } function splitLines(code, preserveEnding = false) { const parts = code.split(/(\r?\n)/g); let index = 0; const lines = []; for (let i = 0; i < parts.length; i += 2) { const line = preserveEnding ? parts[i] + (parts[i + 1] || "") : parts[i]; lines.push([line, index]); index += parts[i].length; index += parts[i + 1]?.length || 0; } return lines; } function isPlainLang(lang) { return !lang || ["plaintext", "txt", "text", "plain"].includes(lang); } function isSpecialLang(lang) { return lang === "ansi" || isPlainLang(lang); } function isNoneTheme(theme) { return theme === "none"; } function isSpecialTheme(theme) { return isNoneTheme(theme); } function addClassToHast(node, className) { if (!className) return node; node.properties ||= {}; node.properties.class ||= []; if (typeof node.properties.class === "string") node.properties.class = node.properties.class.split(/\s+/g); if (!Array.isArray(node.properties.class)) node.properties.class = []; const targets = Array.isArray(className) ? className : className.split(/\s+/g); for (const c of targets) { if (c && !node.properties.class.includes(c)) node.properties.class.push(c); } return node; } function splitToken(token, offsets) { let lastOffset = 0; const tokens = []; for (const offset of offsets) { if (offset > lastOffset) { tokens.push({ ...token, content: token.content.slice(lastOffset, offset), offset: token.offset + lastOffset }); } lastOffset = offset; } if (lastOffset < token.content.length) { tokens.push({ ...token, content: token.content.slice(lastOffset), offset: token.offset + lastOffset }); } return tokens; } function splitTokens(tokens, breakpoints) { const sorted = Array.from(breakpoints instanceof Set ? breakpoints : new Set(breakpoints)).sort((a, b) => a - b); if (!sorted.length) return tokens; return tokens.map((line) => { return line.flatMap((token) => { const breakpointsInToken = sorted.filter((i) => token.offset < i && i < token.offset + token.content.length).map((i) => i - token.offset).sort((a, b) => a - b); if (!breakpointsInToken.length) return token; return splitToken(token, breakpointsInToken); }); }); } async function normalizeGetter(p) { return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r); } function resolveColorReplacements(theme, options) { const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements }; const themeName = typeof theme === "string" ? theme : theme.name; for (const [key, value] of Object.entries(options?.colorReplacements || {})) { if (typeof value === "string") replacements[key] = value; else if (key === themeName) Object.assign(replacements, value); } return replacements; } function applyColorReplacements(color, replacements) { if (!color) return color; return replacements?.[color?.toLowerCase()] || color; } function getTokenStyleObject(token) { const styles = {}; if (token.color) styles.color = token.color; if (token.bgColor) styles["background-color"] = token.bgColor; if (token.fontStyle) { if (token.fontStyle & FontStyle.Italic) styles["font-style"] = "italic"; if (token.fontStyle & FontStyle.Bold) styles["font-weight"] = "bold"; if (token.fontStyle & FontStyle.Underline) styles["text-decoration"] = "underline"; } return styles; } function stringifyTokenStyle(token) { if (typeof token === "string") return token; return Object.entries(token).map(([key, value]) => `${key}:${value}`).join(";"); } function createPositionConverter(code) { const lines = splitLines(code, true).map(([line]) => line); function indexToPos(index) { if (index === code.length) { return { line: lines.length - 1, character: lines[lines.length - 1].length }; } let character = index; let line = 0; for (const lineText of lines) { if (character < lineText.length) break; character -= lineText.length; line++; } return { line, character }; } function posToIndex(line, character) { let index = 0; for (let i = 0; i < line; i++) index += lines[i].length; index += character; return index; } return { lines, indexToPos, posToIndex }; } class ShikiError extends Error { constructor(message) { super(message); this.name = "ShikiError"; } } const _grammarStateMap = /* @__PURE__ */ new WeakMap(); function setLastGrammarStateToMap(keys, state) { _grammarStateMap.set(keys, state); } function getLastGrammarStateFromMap(keys) { return _grammarStateMap.get(keys); } class GrammarState { /** * Theme to Stack mapping */ _stacks = {}; lang; get themes() { return Object.keys(this._stacks); } get theme() { return this.themes[0]; } get _stack() { return this._stacks[this.theme]; } /** * Static method to create a initial grammar state. */ static initial(lang, themes) { return new GrammarState( Object.fromEntries(toArray(themes).map((theme) => [theme, INITIAL])), lang ); } constructor(...args) { if (args.length === 2) { const [stacksMap, lang] = args; this.lang = lang; this._stacks = stacksMap; } else { const [stack, lang, theme] = args; this.lang = lang; this._stacks = { [theme]: stack }; } } /** * Get the internal stack object. * @internal */ getInternalStack(theme = this.theme) { return this._stacks[theme]; } /** * @deprecated use `getScopes` instead */ get scopes() { warnDeprecated("GrammarState.scopes is deprecated, use GrammarState.getScopes() instead"); return getScopes(this._stacks[this.theme]); } getScopes(theme = this.theme) { return getScopes(this._stacks[theme]); } toJSON() { return { lang: this.lang, theme: this.theme, themes: this.themes, scopes: this.scopes }; } } function getScopes(stack) { const scopes = []; const visited = /* @__PURE__ */ new Set(); function pushScope(stack2) { if (visited.has(stack2)) return; visited.add(stack2); const name = stack2?.nameScopesList?.scopeName; if (name) scopes.push(name); if (stack2.parent) pushScope(stack2.parent); } pushScope(stack); return scopes; } function getGrammarStack(state, theme) { if (!(state instanceof GrammarState)) throw new ShikiError("Invalid grammar state"); return state.getInternalStack(theme); } function transformerDecorations() { const map = /* @__PURE__ */ new WeakMap(); function getContext(shiki) { if (!map.has(shiki.meta)) { let normalizePosition = function(p) { if (typeof p === "number") { if (p < 0 || p > shiki.source.length) throw new ShikiError(`Invalid decoration offset: ${p}. Code length: ${shiki.source.length}`); return { ...converter.indexToPos(p), offset: p }; } else { const line = converter.lines[p.line]; if (line === undefined) throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Lines length: ${converter.lines.length}`); if (p.character < 0 || p.character > line.length) throw new ShikiError(`Invalid decoration position ${JSON.stringify(p)}. Line ${p.line} length: ${line.length}`); return { ...p, offset: converter.posToIndex(p.line, p.character) }; } }; const converter = createPositionConverter(shiki.source); const decorations = (shiki.options.decorations || []).map((d) => ({ ...d, start: normalizePosition(d.start), end: normalizePosition(d.end) })); verifyIntersections(decorations); map.set(shiki.meta, { decorations, converter, source: shiki.source }); } return map.get(shiki.meta); } return { name: "shiki:decorations", tokens(tokens) { if (!this.options.decorations?.length) return; const ctx = getContext(this); const breakpoints = ctx.decorations.flatMap((d) => [d.start.offset, d.end.offset]); const splitted = splitTokens(tokens, breakpoints); return splitted; }, code(codeEl) { if (!this.options.decorations?.length) return; const ctx = getContext(this); const lines = Array.from(codeEl.children).filter((i) => i.type === "element" && i.tagName === "span"); if (lines.length !== ctx.converter.lines.length) 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.`); function applyLineSection(line, start, end, decoration) { const lineEl = lines[line]; let text = ""; let startIndex = -1; let endIndex = -1; if (start === 0) startIndex = 0; if (end === 0) endIndex = 0; if (end === Number.POSITIVE_INFINITY) endIndex = lineEl.children.length; if (startIndex === -1 || endIndex === -1) { for (let i = 0; i < lineEl.children.length; i++) { text += stringify(lineEl.children[i]); if (startIndex === -1 && text.length === start) startIndex = i + 1; if (endIndex === -1 && text.length === end) endIndex = i + 1; } } if (startIndex === -1) throw new ShikiError(`Failed to find start index for decoration ${JSON.stringify(decoration.start)}`); if (endIndex === -1) throw new ShikiError(`Failed to find end index for decoration ${JSON.stringify(decoration.end)}`); const children = lineEl.children.slice(startIndex, endIndex); if (!decoration.alwaysWrap && children.length === lineEl.children.length) { applyDecoration(lineEl, decoration, "line"); } else if (!decoration.alwaysWrap && children.length === 1 && children[0].type === "element") { applyDecoration(children[0], decoration, "token"); } else { const wrapper = { type: "element", tagName: "span", properties: {}, children }; applyDecoration(wrapper, decoration, "wrapper"); lineEl.children.splice(startIndex, children.length, wrapper); } } function applyLine(line, decoration) { lines[line] = applyDecoration(lines[line], decoration, "line"); } function applyDecoration(el, decoration, type) { const properties = decoration.properties || {}; const transform = decoration.transform || ((i) => i); el.tagName = decoration.tagName || "span"; el.properties = { ...el.properties, ...properties, class: el.properties.class }; if (decoration.properties?.class) addClassToHast(el, decoration.properties.class); el = transform(el, type) || el; return el; } const lineApplies = []; const sorted = ctx.decorations.sort((a, b) => b.start.offset - a.start.offset); for (const decoration of sorted) { const { start, end } = decoration; if (start.line === end.line) { applyLineSection(start.line, start.character, end.character, decoration); } else if (start.line < end.line) { applyLineSection(start.line, start.character, Number.POSITIVE_INFINITY, decoration); for (let i = start.line + 1; i < end.line; i++) lineApplies.unshift(() => applyLine(i, decoration)); applyLineSection(end.line, 0, end.character, decoration); } } lineApplies.forEach((i) => i()); } }; } function verifyIntersections(items) { for (let i = 0; i < items.length; i++) { const foo = items[i]; if (foo.start.offset > foo.end.offset) throw new ShikiError(`Invalid decoration range: ${JSON.stringify(foo.start)} - ${JSON.stringify(foo.end)}`); for (let j = i + 1; j < items.length; j++) { const bar = items[j]; const isFooHasBarStart = foo.start.offset < bar.start.offset && bar.start.offset < foo.end.offset; const isFooHasBarEnd = foo.start.offset < bar.end.offset && bar.end.offset < foo.end.offset; const isBarHasFooStart = bar.start.offset < foo.start.offset && foo.start.offset < bar.end.offset; const isBarHasFooEnd = bar.start.offset < foo.end.offset && foo.end.offset < bar.end.offset; if (isFooHasBarStart || isFooHasBarEnd || isBarHasFooStart || isBarHasFooEnd) { if (isFooHasBarEnd && isFooHasBarEnd) continue; if (isBarHasFooStart && isBarHasFooEnd) continue; throw new ShikiError(`Decorations ${JSON.stringify(foo.start)} and ${JSON.stringify(bar.start)} intersect.`); } } } } function stringify(el) { if (el.type === "text") return el.value; if (el.type === "element") return el.children.map(stringify).join(""); return ""; } const builtInTransformers = [ /* @__PURE__ */ transformerDecorations() ]; function getTransformers(options) { return [ ...options.transformers || [], ...builtInTransformers ]; } // src/colors.ts var namedColors = [ "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", "brightBlack", "brightRed", "brightGreen", "brightYellow", "brightBlue", "brightMagenta", "brightCyan", "brightWhite" ]; // src/decorations.ts var decorations = { 1: "bold", 2: "dim", 3: "italic", 4: "underline", 7: "reverse", 9: "strikethrough" }; // src/parser.ts function findSequence(value, position) { const nextEscape = value.indexOf("\x1B[", position); if (nextEscape !== -1) { const nextClose = value.indexOf("m", nextEscape); return { sequence: value.substring(nextEscape + 2, nextClose).split(";"), startPosition: nextEscape, position: nextClose + 1 }; } return { position: value.length }; } function parseColor(sequence, index) { let offset = 1; const colorMode = sequence[index + offset++]; let color; if (colorMode === "2") { const rgb = [ sequence[index + offset++], sequence[index + offset++], sequence[index + offset] ].map((x) => Number.parseInt(x)); if (rgb.length === 3 && !rgb.some((x) => Number.isNaN(x))) { color = { type: "rgb", rgb }; } } else if (colorMode === "5") { const colorIndex = Number.parseInt(sequence[index + offset]); if (!Number.isNaN(colorIndex)) { color = { type: "table", index: Number(colorIndex) }; } } return [offset, color]; } function parseSequence(sequence) { const commands = []; for (let i = 0; i < sequence.length; i++) { const code = sequence[i]; const codeInt = Number.parseInt(code); if (Number.isNaN(codeInt)) continue; if (codeInt === 0) { commands.push({ type: "resetAll" }); } else if (codeInt <= 9) { const decoration = decorations[codeInt]; if (decoration) { commands.push({ type: "setDecoration", value: decorations[codeInt] }); } } else if (codeInt <= 29) { const decoration = decorations[codeInt - 20]; if (decoration) { commands.push({ type: "resetDecoration", value: decoration }); } } else if (codeInt <= 37) { commands.push({ type: "setForegroundColor", value: { type: "named", name: namedColors[codeInt - 30] } }); } else if (codeInt === 38) { const [offset, color] = parseColor(sequence, i); if (color) { commands.push({ type: "setForegroundColor", value: color }); } i += offset; } else if (codeInt === 39) { commands.push({ type: "resetForegroundColor" }); } else if (codeInt <= 47) { commands.push({ type: "setBackgroundColor", value: { type: "named", name: namedColors[codeInt - 40] } }); } else if (codeInt === 48) { const [offset, color] = parseColor(sequence, i); if (color) { commands.push({ type: "setBackgroundColor", value: color }); } i += offset; } else if (codeInt === 49) { commands.push({ type: "resetBackgroundColor" }); } else if (codeInt >= 90 && codeInt <= 97) { commands.push({ type: "setForegroundColor", value: { type: "named", name: namedColors[codeInt - 90 + 8] } }); } else if (codeInt >= 100 && codeInt <= 107) { commands.push({ type: "setBackgroundColor", value: { type: "named", name: namedColors[codeInt - 100 + 8] } }); } } return commands; } function createAnsiSequenceParser() { let foreground = null; let background = null; let decorations2 = /* @__PURE__ */ new Set(); return { parse(value) { const tokens = []; let position = 0; do { const findResult = findSequence(value, position); const text = findResult.sequence ? value.substring(position, findResult.startPosition) : value.substring(position); if (text.length > 0) { tokens.push({ value: text, foreground, background, decorations: new Set(decorations2) }); } if (findResult.sequence) { const commands = parseSequence(findResult.sequence); for (const styleToken of commands) { if (styleToken.type === "resetAll") { foreground = null; background = null; decorations2.clear(); } else if (styleToken.type === "resetForegroundColor") { foreground = null; } else if (styleToken.type === "resetBackgroundColor") { background = null; } else if (styleToken.type === "resetDecoration") { decorations2.delete(styleToken.value); } } for (const styleToken of commands) { if (styleToken.type === "setForegroundColor") { foreground = styleToken.value; } else if (styleToken.type === "setBackgroundColor") { background = styleToken.value; } else if (styleToken.type === "setDecoration") { decorations2.add(styleToken.value); } } } position = findResult.position; } while (position < value.length); return tokens; } }; } // src/palette.ts var defaultNamedColorsMap = { black: "#000000", red: "#bb0000", green: "#00bb00", yellow: "#bbbb00", blue: "#0000bb", magenta: "#ff00ff", cyan: "#00bbbb", white: "#eeeeee", brightBlack: "#555555", brightRed: "#ff5555", brightGreen: "#00ff00", brightYellow: "#ffff55", brightBlue: "#5555ff", brightMagenta: "#ff55ff", brightCyan: "#55ffff", brightWhite: "#ffffff" }; function createColorPalette(namedColorsMap = defaultNamedColorsMap) { function namedColor(name) { return namedColorsMap[name]; } function rgbColor(rgb) { return `#${rgb.map((x) => Math.max(0, Math.min(x, 255)).toString(16).padStart(2, "0")).join("")}`; } let colorTable; function getColorTable() { if (colorTable) { return colorTable; } colorTable = []; for (let i = 0; i < namedColors.length; i++) { colorTable.push(namedColor(namedColors[i])); } let levels = [0, 95, 135, 175, 215, 255]; for (let r = 0; r < 6; r++) { for (let g = 0; g < 6; g++) { for (let b = 0; b < 6; b++) { colorTable.push(rgbColor([levels[r], levels[g], levels[b]])); } } } let level = 8; for (let i = 0; i < 24; i++, level += 10) { colorTable.push(rgbColor([level, level, level])); } return colorTable; } function tableColor(index) { return getColorTable()[index]; } function value(color) { switch (color.type) { case "named": return namedColor(color.name); case "rgb": return rgbColor(color.rgb); case "table": return tableColor(color.index); } } return { value }; } function tokenizeAnsiWithTheme(theme, fileContents, options) { const colorReplacements = resolveColorReplacements(theme, options); const lines = splitLines(fileContents); const colorPalette = createColorPalette( Object.fromEntries( namedColors.map((name) => [ name, theme.colors?.[`terminal.ansi${name[0].toUpperCase()}${name.substring(1)}`] ]) ) ); const parser = createAnsiSequenceParser(); return lines.map( (line) => parser.parse(line[0]).map((token) => { let color; let bgColor; if (token.decorations.has("reverse")) { color = token.background ? colorPalette.value(token.background) : theme.bg; bgColor = token.foreground ? colorPalette.value(token.foreground) : theme.fg; } else { color = token.foreground ? colorPalette.value(token.foreground) : theme.fg; bgColor = token.background ? colorPalette.value(token.background) : undefined; } color = applyColorReplacements(color, colorReplacements); bgColor = applyColorReplacements(bgColor, colorReplacements); if (token.decorations.has("dim")) color = dimColor(color); let fontStyle = FontStyle.None; if (token.decorations.has("bold")) fontStyle |= FontStyle.Bold; if (token.decorations.has("italic")) fontStyle |= FontStyle.Italic; if (token.decorations.has("underline")) fontStyle |= FontStyle.Underline; return { content: token.value, offset: line[1], // TODO: more accurate offset? might need to fork ansi-sequence-parser color, bgColor, fontStyle }; }) ); } function dimColor(color) { const hexMatch = color.match(/#([0-9a-f]{3})([0-9a-f]{3})?([0-9a-f]{2})?/); if (hexMatch) { if (hexMatch[3]) { const alpha = Math.round(Number.parseInt(hexMatch[3], 16) / 2).toString(16).padStart(2, "0"); return `#${hexMatch[1]}${hexMatch[2]}${alpha}`; } else if (hexMatch[2]) { return `#${hexMatch[1]}${hexMatch[2]}80`; } else { return `#${Array.from(hexMatch[1]).map((x) => `${x}${x}`).join("")}80`; } } const cssVarMatch = color.match(/var\((--[\w-]+-ansi-[\w-]+)\)/); if (cssVarMatch) return `var(${cssVarMatch[1]}-dim)`; return color; } function codeToTokensBase(internal, code, options = {}) { const { lang = "text", theme: themeName = internal.getLoadedThemes()[0] } = options; if (isPlainLang(lang) || isNoneTheme(themeName)) return splitLines(code).map((line) => [{ content: line[0], offset: line[1] }]); const { theme, colorMap } = internal.setTheme(themeName); if (lang === "ansi") return tokenizeAnsiWithTheme(theme, code, options); const _grammar = internal.getLanguage(lang); if (options.grammarState) { if (options.grammarState.lang !== _grammar.name) { throw new ShikiError$1(`Grammar state language "${options.grammarState.lang}" does not match highlight language "${_grammar.name}"`); } if (!options.grammarState.themes.includes(theme.name)) { throw new ShikiError$1(`Grammar state themes "${options.grammarState.themes}" do not contain highlight theme "${theme.name}"`); } } return tokenizeWithTheme(code, _grammar, theme, colorMap, options); } function getLastGrammarState(...args) { if (args.length === 2) { return getLastGrammarStateFromMap(args[1]); } const [internal, code, options = {}] = args; const { lang = "text", theme: themeName = internal.getLoadedThemes()[0] } = options; if (isPlainLang(lang) || isNoneTheme(themeName)) throw new ShikiError$1("Plain language does not have grammar state"); if (lang === "ansi") throw new ShikiError$1("ANSI language does not have grammar state"); const { theme, colorMap } = internal.setTheme(themeName); const _grammar = internal.getLanguage(lang); return new GrammarState( _tokenizeWithTheme(code, _grammar, theme, colorMap, options).stateStack, _grammar.name, theme.name ); } function tokenizeWithTheme(code, grammar, theme, colorMap, options) { const result = _tokenizeWithTheme(code, grammar, theme, colorMap, options); const grammarState = new GrammarState( _tokenizeWithTheme(code, grammar, theme, colorMap, options).stateStack, grammar.name, theme.name ); setLastGrammarStateToMap(result.tokens, grammarState); return result.tokens; } function _tokenizeWithTheme(code, grammar, theme, colorMap, options) { const colorReplacements = resolveColorReplacements(theme, options); const { tokenizeMaxLineLength = 0, tokenizeTimeLimit = 500 } = options; const lines = splitLines(code); let stateStack = options.grammarState ? getGrammarStack(options.grammarState, theme.name) ?? INITIAL : options.grammarContextCode != null ? _tokenizeWithTheme( options.grammarContextCode, grammar, theme, colorMap, { ...options, grammarState: undefined, grammarContextCode: undefined } ).stateStack : INITIAL; let actual = []; const final = []; for (let i = 0, len = lines.length; i < len; i++) { const [line, lineOffset] = lines[i]; if (line === "") { actual = []; final.push([]); continue; } if (tokenizeMaxLineLength > 0 && line.length >= tokenizeMaxLineLength) { actual = []; final.push([{ content: line, offset: lineOffset, color: "", fontStyle: 0 }]); continue; } let resultWithScopes; let tokensWithScopes; let tokensWithScopesIndex; if (options.includeExplanation) { resultWithScopes = grammar.tokenizeLine(line, stateStack); tokensWithScopes = resultWithScopes.tokens; tokensWithScopesIndex = 0; } const result = grammar.tokenizeLine2(line, stateStack, tokenizeTimeLimit); const tokensLength = result.tokens.length / 2; for (let j = 0; j < tokensLength; j++) { const startIndex = result.tokens[2 * j]; const nextStartIndex = j + 1 < tokensLength ? result.tokens[2 * j + 2] : line.length; if (startIndex === nextStartIndex) continue; const metadata = result.tokens[2 * j + 1]; const color = applyColorReplacements( colorMap[EncodedTokenMetadata.getForeground(metadata)], colorReplacements ); const fontStyle = EncodedTokenMetadata.getFontStyle(metadata); const token = { content: line.substring(startIndex, nextStartIndex), offset: lineOffset + startIndex, color, fontStyle }; if (options.includeExplanation) { const themeSettingsSelectors = []; if (options.includeExplanation !== "scopeName") { for (const setting of theme.settings) { let selectors; switch (typeof setting.scope) { case "string": selectors = setting.scope.split(/,/).map((scope) => scope.trim()); break; case "object": selectors = setting.scope; break; default: continue; } themeSettingsSelectors.push({ settings: setting, selectors: selectors.map((selector) => selector.split(/ /)) }); } } token.explanation = []; let offset = 0; while (startIndex + offset < nextStartIndex) { const tokenWithScopes = tokensWithScopes[tokensWithScopesIndex]; const tokenWithScopesText = line.substring( tokenWithScopes.startIndex, tokenWithScopes.endIndex ); offset += tokenWithScopesText.length; token.explanation.push({ content: tokenWithScopesText, scopes: options.includeExplanation === "scopeName" ? explainThemeScopesNameOnly( tokenWithScopes.scopes ) : explainThemeScopesFull( themeSettingsSelectors, tokenWithScopes.scopes ) }); tokensWithScopesIndex += 1; } } actual.push(token); } final.push(actual); actual = []; stateStack = result.ruleStack; } return { tokens: final, stateStack }; } function explainThemeScopesNameOnly(scopes) { return scopes.map((scope) => ({ scopeName: scope })); } function explainThemeScopesFull(themeSelectors, scopes) { const result = []; for (let i = 0, len = scopes.length; i < len; i++) { const scope = scopes[i]; result[i] = { scopeName: scope, themeMatches: explainThemeScope(themeSelectors, scope, scopes.slice(0, i)) }; } return result; } function matchesOne(selector, scope) { return selector === scope || scope.substring(0, selector.length) === selector && scope[selector.length] === "."; } function matches(selectors, scope, parentScopes) { if (!matchesOne(selectors[selectors.length - 1], scope)) return false; let selectorParentIndex = selectors.length - 2; let parentIndex = parentScopes.length - 1; while (selectorParentIndex >= 0 && parentIndex >= 0) { if (matchesOne(selectors[selectorParentIndex], parentScopes[parentIndex])) selectorParentIndex -= 1; parentIndex -= 1; } if (selectorParentIndex === -1) return true; return false; } function explainThemeScope(themeSettingsSelectors, scope, parentScopes) { const result = []; for (const { selectors, settings } of themeSettingsSelectors) { for (const selectorPieces of selectors) { if (matches(selectorPieces, scope, parentScopes)) { result.push(settings); break; } } } return result; } function codeToTokensWithThemes(internal, code, options) { const themes = Object.entries(options.themes).filter((i) => i[1]).map((i) => ({ color: i[0], theme: i[1] })); const themedTokens = themes.map((t) => { const tokens2 = codeToTokensBase(internal, code, { ...options, theme: t.theme }); const state = getLastGrammarStateFromMap(tokens2); const theme = typeof t.theme === "string" ? t.theme : t.theme.name; return { tokens: tokens2, state, theme }; }); const tokens = syncThemesTokenization( ...themedTokens.map((i) => i.tokens) ); const mergedTokens = tokens[0].map( (line, lineIdx) => line.map((_token, tokenIdx) => { const mergedToken = { content: _token.content, variants: {}, offset: _token.offset }; if ("includeExplanation" in options && options.includeExplanation) { mergedToken.explanation = _token.explanation; } tokens.forEach((t, themeIdx) => { const { content: _, explanation: __, offset: ___, ...styles } = t[lineIdx][tokenIdx]; mergedToken.variants[themes[themeIdx].color] = styles; }); return mergedToken; }) ); const mergedGrammarState = themedTokens[0].state ? new GrammarState( Object.fromEntries(themedTokens.map((s) => [s.theme, s.state?.getInternalStack(s.theme)])), themedTokens[0].state.lang ) : undefined; if (mergedGrammarState) setLastGrammarStateToMap(mergedTokens, mergedGrammarState); return mergedTokens; } function syncThemesTokenization(...themes) { const outThemes = themes.map(() => []); const count = themes.length; for (let i = 0; i < themes[0].length; i++) { const lines = themes.map((t) => t[i]); const outLines = outThemes.map(() => []); outThemes.forEach((t, i2) => t.push(outLines[i2])); const indexes = lines.map(() => 0); const current = lines.map((l) => l[0]); while (current.every((t) => t)) { const minLength = Math.min(...current.map((t) => t.content.length)); for (let n = 0; n < count; n++) { const token = current[n]; if (token.content.length === minLength) { outLines[n].push(token); indexes[n] += 1; current[n] = lines[n][indexes[n]]; } else { outLines[n].push({ ...token, content: token.content.slice(0, minLength) }); current[n] = { ...token, content: token.content.slice(minLength), offset: token.offset + minLength }; } } } } return outThemes; } function codeToTokens(internal, code, options) { let bg; let fg; let tokens; let themeName; let rootStyle; let grammarState; if ("themes" in options) { const { defaultColor = "light", cssVariablePrefix = "--shiki-" } = options; const themes = Object.entries(options.themes).filter((i) => i[1]).map((i) => ({ color: i[0], theme: i[1] })).sort((a, b) => a.color === defaultColor ? -1 : b.color === defaultColor ? 1 : 0); if (themes.length === 0) throw new ShikiError$1("`themes` option must not be empty"); const themeTokens = codeToTokensWithThemes( internal, code, options ); grammarState = getLastGrammarStateFromMap(themeTokens); if (defaultColor && !themes.find((t) => t.color === defaultColor)) throw new ShikiError$1(`\`themes\` option must contain the defaultColor key \`${defaultColor}\``); const themeRegs = themes.map((t) => internal.getTheme(t.theme)); const themesOrder = themes.map((t) => t.color); tokens = themeTokens.map((line) => line.map((token) => mergeToken(token, themesOrder, cssVariablePrefix, defaultColor))); if (grammarState) setLastGrammarStateToMap(tokens, grammarState); const themeColorReplacements = themes.map((t) => resolveColorReplacements(t.theme, options)); fg = themes.map((t, idx) => (idx === 0 && defaultColor ? "" : `${cssVariablePrefix + t.color}:`) + (applyColorReplacements(themeRegs[idx].fg, themeColorReplacements[idx]) || "inherit")).join(";"); bg = themes.map((t, idx) => (idx === 0 && defaultColor ? "" : `${cssVariablePrefix + t.color}-bg:`) + (applyColorReplacements(themeRegs[idx].bg, themeColorReplacements[idx]) || "inherit")).join(";"); themeName = `shiki-themes ${themeRegs.map((t) => t.name).join(" ")}`; rootStyle = defaultColor ? undefined : [fg, bg].join(";"); } else if ("theme" in options) { const colorReplacements = resolveColorReplacements(options.theme, options); tokens = codeToTokensBase( internal, code, options ); const _theme = internal.getTheme(options.theme); bg = applyColorReplacements(_theme.bg, colorReplacements); fg = applyColorReplacements(_theme.fg, colorReplacements); themeName = _theme.name; grammarState = getLastGrammarStateFromMap(tokens); } else { throw new ShikiError$1("Invalid options, either `theme` or `themes` must be provided"); } return { tokens, fg, bg, themeName, rootStyle, grammarState }; } function mergeToken(merged, variantsOrder, cssVariablePrefix, defaultColor) { const token = { content: merged.content, explanation: merged.explanation, offset: merged.offset }; const styles = variantsOrder.map((t) => getTokenStyleObject(merged.variants[t])); const styleKeys = new Set(styles.flatMap((t) => Object.keys(t))); const mergedStyles = {}; styles.forEach((cur, idx) => { for (const key of styleKeys) { const value = cur[key] || "inherit"; if (idx === 0 && defaultColor) { mergedStyles[key] = value; } else { const keyName = key === "color" ? "" : key === "background-color" ? "-bg" : `-${key}`; const varKey = cssVariablePrefix + variantsOrder[idx] + (key === "color" ? "" : keyName); mergedStyles[varKey] = value; } } }); token.htmlStyle = mergedStyles; return token; } function codeToHast(internal, code, options, transformerContext = { meta: {}, options, codeToHast: (_code, _options) => codeToHast(internal, _code, _options), codeToTokens: (_code, _options) => codeToTokens(internal, _code, _options) }) { let input = code; for (const transformer of getTransformers(options)) input = transformer.preprocess?.call(transformerContext, input, options) || input; let { tokens, fg, bg, themeName, rootStyle, grammarState } = codeToTokens(internal, input, options); const { mergeWhitespaces = true } = options; if (mergeWhitespaces === true) tokens = mergeWhitespaceTokens(tokens); else if (mergeWhitespaces === "never") tokens = splitWhitespaceTokens(tokens); const contextSource = { ...transformerContext, get source() { return input; } }; for (const transformer of getTransformers(options)) tokens = transformer.tokens?.call(contextSource, tokens) || tokens; return tokensToHast( tokens, { ...options, fg, bg, themeName, rootStyle }, contextSource, grammarState ); } function tokensToHast(tokens, options, transformerContext, grammarState = getLastGrammarStateFromMap(tokens)) { const transformers = getTransformers(options); const lines = []; const root = { type: "root", children: [] }; const { structure = "classic", tabindex = "0" } = options; let preNode = { type: "element", tagName: "pre", properties: { class: `shiki ${options.themeName || ""}`, style: options.rootStyle || `background-color:${options.bg};color:${options.fg}`, ...tabindex !== false && tabindex != null ? { tabindex: tabindex.toString() } : {}, ...Object.fromEntries( Array.from( Object.entries(options.meta || {}) ).filter(([key]) => !key.startsWith("_")) ) }, children: [] }; let codeNode = { type: "element", tagName: "code", properties: {}, children: lines }; const lineNodes = []; const context = { ...transformerContext, structure, addClassToHast, get source() { return transformerContext.source; }, get tokens() { return tokens; }, get options() { return options; }, get root() { return root; }, get pre() { return preNode; }, get code() { return codeNode; }, get lines() { return lineNodes; } }; tokens.forEach((line, idx) => { if (idx) { if (structure === "inline") root.children.push({ type: "element", tagName: "br", properties: {}, children: [] }); else if (structure === "classic") lines.push({ type: "text", value: "\n" }); } let lineNode = { type: "element", tagName: "span", properties: { class: "line" }, children: [] }; let col = 0; for (const token of line) { let tokenNode = { type: "element", tagName: "span", properties: { ...token.htmlAttrs }, children: [{ type: "text", value: token.content }] }; if (typeof token.htmlStyle === "string") warnDeprecated("`htmlStyle` as a string is deprecated. Use an object instead."); const style = stringifyTokenStyle(token.htmlStyle || getTokenStyleObject(token)); if (style) tokenNode.properties.style = style; for (const transformer of transformers) tokenNode = transformer?.span?.call(context, tokenNode, idx + 1, col, lineNode, token) || tokenNode; if (structure === "inline") root.children.push(tokenNode); else if (structure === "classic") lineNode.children.push(tokenNode); col += token.content.length; } if (structure === "classic") { for (const transformer of transformers) lineNode = transformer?.line?.call(context, lineNode, idx + 1) || lineNode; lineNodes.push(lineNode); lines.push(lineNode); } }); if (structure === "classic") { for (const transformer of transformers) codeNode = transformer?.code?.call(context, codeNode) || codeNode; preNode.children.push(codeNode); for (const transformer of transformers) preNode = transformer?.pre?.call(context, preNode) || preNode; root.children.push(preNode); } let result = root; for (const transformer of transformers) result = transformer?.root?.call(context, result) || result; if (grammarState) setLastGrammarStateToMap(result, grammarState); return result; } function mergeWhitespaceTokens(tokens) { return tokens.map((line) => { const newLine = []; let carryOnContent = ""; let firstOffset = 0; line.forEach((token, idx) => { const isUnderline = token.fontStyle && token.fontStyle & FontStyle.Underline; const couldMerge = !isUnderline; if (couldMerge && token.content.match(/^\s+$/) && line[idx + 1]) { if (!firstOffset) firstOffset = token.offset; carryOnContent += token.content; } else { if (carryOnContent) { if (couldMerge) { newLine.push({ ...token, offset: firstOffset, content: carryOnContent + token.content }); } else { newLine.push( { content: carryOnContent, offset: firstOffset }, token ); } firstOffset = 0; carryOnContent = ""; } else { newLine.push(token); } } }); return newLine; }); } function splitWhitespaceTokens(tokens) { return tokens.map((line) => { return line.flatMap((token) => { if (token.content.match(/^\s+$/)) return token; const match = token.content.match(/^(\s*)(.*?)(\s*)$/); if (!match) return token; const [, leading, content, trailing] = match; if (!leading && !trailing) return token; const expanded = [{ ...token, offset: token.offset + leading.length, content }]; if (leading) { expanded.unshift({ content: leading, offset: token.offset }); } if (trailing) { expanded.push({ content: trailing, offset: token.offset + leading.length + content.length }); } return expanded; }); }); } function codeToHtml(internal, code, options) { const context = { meta: {}, options, codeToHast: (_code, _options) => codeToHast(internal, _code, _options), codeToTokens: (_code, _options) => codeToTokens(internal, _code, _options) }; let result = toHtml(codeToHast(internal, code, options, context)); for (const transformer of getTransformers(options)) result = transformer.postprocess?.call(context, result, options) || result; return result; } const VSCODE_FALLBACK_EDITOR_FG = { light: "#333333", dark: "#bbbbbb" }; const VSCODE_FALLBACK_EDITOR_BG = { light: "#fffffe", dark: "#1e1e1e" }; const RESOLVED_KEY = "__shiki_resolved"; function normalizeTheme(rawTheme) { if (rawTheme?.[RESOLVED_KEY]) return rawTheme; const theme = { ...rawTheme }; if (theme.tokenColors && !theme.settings) { theme.settings = theme.tokenColors; delete theme.tokenColors; } theme.type ||= "dark"; theme.colorReplacements = { ...theme.colorReplacements }; theme.settings ||= []; let { bg, fg } = theme; if (!bg || !fg) { const globalSetting = theme.settings ? theme.settings.find((s) => !s.name && !s.scope) : undefined; if (globalSetting?.settings?.foreground) fg = globalSetting.settings.foreground; if (globalSetting?.settings?.background) bg = globalSetting.settings.background; if (!fg && theme?.colors?.["editor.foreground"]) fg = theme.colors["editor.foreground"]; if (!bg && theme?.colors?.["editor.background"]) bg = theme.colors["editor.background"]; if (!fg) fg = theme.type === "light" ? VSCODE_FALLBACK_EDITOR_FG.light : VSCODE_FALLBACK_EDITOR_FG.dark; if (!bg) bg = theme.type === "light" ? VSCODE_FALLBACK_EDITOR_BG.light : VSCODE_FALLBACK_EDITOR_BG.dark; theme.fg = fg; theme.bg = bg; } if (!(theme.settings[0] && theme.settings[0].settings && !theme.settings[0].scope)) { theme.settings.unshift({ settings: { foreground: theme.fg, background: theme.bg } }); } let replacementCount = 0; const replacementMap = /* @__PURE__ */ new Map(); function getReplacementColor(value) { if (replacementMap.has(value)) return replacementMap.get(value); replacementCount += 1; const hex = `#${replacementCount.toString(16).padStart(8, "0").toLowerCase()}`; if (theme.colorReplacements?.[`#${hex}`]) return getReplacementColor(value); replacementMap.set(value, hex); return hex; } theme.settings = theme.settings.map((setting) => { const replaceFg = setting.settings?.foreground && !setting.settings.foreground.startsWith("#"); const replaceBg = setting.settings?.background && !setting.settings.background.startsWith("#"); if (!replaceFg && !replaceBg) return setting; const clone = { ...setting, settings: { ...setting.settings } }; if (replaceFg) { const replacement = getReplacementColor(setting.settings.foreground); theme.colorReplacements[replacement] = setting.settings.foreground; clone.settings.foreground = replacement; } if (replaceBg) { const replacement = getReplacementColor(setting.settings.background); theme.colorReplacements[replacement] = setting.settings.background; clone.settings.background = replacement; } return clone; }); for (const key of Object.keys(theme.colors || {})) { if (key === "editor.foreground" || key === "editor.background" || key.startsWith("terminal.ansi")) { if (!theme.colors[key]?.startsWith("#")) { const replacement = getReplacementColor(theme.colors[key]); theme.colorReplacements[replacement] = theme.colors[key]; theme.colors[key] = replacement; } } } Object.defineProperty(theme, RESOLVED_KEY, { enumerable: false, writable: false, value: true }); return theme; } async function resolveLangs(langs) { return Array.from(new Set((await Promise.all( langs.filter((l) => !isSpecialLang(l)).map(async (lang) => await normalizeGetter(lang).then((r) => Array.isArray(r) ? r : [r])) )).flat())); } async function resolveThemes(themes) { const resolved = await Promise.all( themes.map( async (theme) => isSpecialTheme(theme) ? null : normalizeTheme(await normalizeGetter(theme)) ) ); return resolved.filter((i) => !!i); } class Registry extends Registry$1 { constructor(_resolver, _themes, _langs, _alias = {}) { super(_resolver); this._resolver = _resolver; this._themes = _themes; this._langs = _langs; this._alias = _alias; this._themes.map((t) => this.loadTheme(t)); this.loadLanguages(this._langs); } _resolvedThemes = /* @__PURE__ */ new Map(); _resolvedGrammars = /* @__PURE__ */ new Map(); _langMap = /* @__PURE__ */ new Map(); _langGraph = /* @__PURE__ */ new Map(); _textmateThemeCache = /* @__PURE__ */ new WeakMap(); _loadedThemesCache = null; _loadedLanguagesCache = null; getTheme(theme) { if (typeof theme === "string") return this._resolvedThemes.get(theme); else return this.loadTheme(theme); } loadTheme(theme) { const _theme = normalizeTheme(theme); if (_theme.name) { this._resolvedThemes.set(_theme.name, _theme); this._loadedThemesCache = null; } return _theme; } getLoadedThemes() { if (!this._loadedThemesCache) this._loadedThemesCache = [...this._resolvedThemes.keys()]; return this._loadedThemesCache; } // Override and re-implement this method to cache the textmate themes as `TextMateTheme.createFromRawTheme` // is expensive. Themes can switch often especially for dual-theme support. // // The parent class also accepts `colorMap` as the second parameter, but since we don't use that, // we omit here so it's easier to cache the themes. setTheme(theme) { let textmateTheme = this._textmateThemeCache.get(theme); if (!textmateTheme) { textmateTheme = Theme.createFromRawTheme(theme); this._textmateThemeCache.set(theme, textmateTheme); } this._syncRegistry.setTheme(textmateTheme); } getGrammar(name) { if (this._alias[name]) { const resolved = /* @__PURE__ */ new Set([name]); while (this._alias[name]) { name = this._alias[name]; if (resolved.has(name)) throw new ShikiError(`Circular alias \`${Array.from(resolved).join(" -> ")} -> ${name}\``); resolved.add(name); } } return this._resolvedGrammars.get(name); } loadLanguage(lang) { if (this.getGrammar(lang.name)) return; const embeddedLazilyBy = new Set( [...this._langMap.values()].filter((i) => i.embeddedLangsLazy?.includes(lang.name)) ); this._resolver.addLanguage(lang); const grammarConfig = { balancedBracketSelectors: lang.balancedBracketSelectors || ["*"], unbalancedBracketSelectors: lang.unbalancedBracketSelectors || [] }; this._syncRegistry._rawGrammars.set(lang.scopeName, lang); const g = this.loadGrammarWithConfiguration(lang.scopeName, 1, grammarConfig); g.name = lang.name; this._resolvedGrammars.set(lang.name, g); if (lang.aliases) { lang.aliases.forEach((alias) => { this._alias[alias] = lang.name; }); } this._loadedLanguagesCache = null; if (embeddedLazilyBy.size) { for (const e of embeddedLazilyBy) { this._resolvedGrammars.delete(e.name); this._loadedLanguagesCache = null; this._syncRegistry?._injectionGrammars?.delete(e.scopeName); this._syncRegistry?._grammars?.delete(e.scopeName); this.loadLanguage(this._langMap.get(e.name)); } } } dispose() { super.dispose(); this._resolvedThemes.clear(); this._resolvedGrammars.clear(); this._langMap.clear(); this._langGraph.clear(); this._loadedThemesCache = null; } loadLanguages(langs) { for (const lang of langs) this.resolveEmbeddedLanguages(lang); const langsGraphArray = Array.from(this._langGraph.entries()); const missingLangs = langsGraphArray.filter(([_, lang]) => !lang); if (missingLangs.length) { const dependents = langsGraphArray.filter(([_, lang]) => lang && lang.embeddedLangs?.some((l) => missingLangs.map(([name]) => name).includes(l))).filter((lang) => !missingLangs.includes(lang)); throw new ShikiError(`Missing languages ${missingLangs.map(([name]) => `\`${name}\``).join(", ")}, required by ${dependents.map(([name]) => `\`${name}\``).join(", ")}`); } for (const [_, lang] of langsGraphArray) this._resolver.addLanguage(lang); for (const [_, lang] of langsGraphArray) this.loadLanguage(lang); } getLoadedLanguages() { if (!this._loadedLanguagesCache) { this._loadedLanguagesCache = [ .../* @__PURE__ */ new Set([...this._resolvedGrammars.keys(), ...Object.keys(this._alias)]) ]; } return this._loadedLanguagesCache; } resolveEmbeddedLanguages(lang) { this._langMap.set(lang.name, lang); this._langGraph.set(lang.name, lang); if (lang.embeddedLangs) { for (const embeddedLang of lang.embeddedLangs) this._langGraph.set(embeddedLang, this._langMap.get(embeddedLang)); } } } class Resolver { _langs = /* @__PURE__ */ new Map(); _scopeToLang = /* @__PURE__ */ new Map(); _injections = /* @__PURE__ */ new Map(); _onigLib; constructor(engine, langs) { this._onigLib = { createOnigScanner: (patterns) => engine.createScanner(patterns), createOnigString: (s) => engine.createString(s) }; langs.forEach((i) => this.addLanguage(i)); } get onigLib() { return this._onigLib; } getLangRegistration(langIdOrAlias) { return this._langs.get(langIdOrAlias); } loadGrammar(scopeName) { return this._scopeToLang.get(scopeName); } addLanguage(l) { this._langs.set(l.name, l); if (l.aliases) { l.aliases.forEach((a) => { this._langs.set(a, l); }); } this._scopeToLang.set(l.scopeName, l); if (l.injectTo) { l.injectTo.forEach((i) => { if (!this._injections.get(i)) this._injections.set(i, []); this._injections.get(i).push(l.scopeName); }); } } getInjections(scopeName) { const scopeParts = scopeName.split("."); let injections = []; for (let i = 1; i <= scopeParts.length; i++) { const subScopeName = scopeParts.slice(0, i).join("."); injections = [...injections, ...this._injections.get(subScopeName) || []]; } return injections; } } let instancesCount = 0; function createShikiInternalSync(options) { instancesCount += 1; if (options.warnings !== false && instancesCount >= 10 && instancesCount % 10 === 0) 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.`); let isDisposed = false; if (!options.engine) throw new ShikiError("`engine` option is required for synchronous mode"); const langs = (options.langs || []).flat(1); const themes = (options.themes || []).flat(1).map(normalizeTheme); const resolver = new Resolver(options.engine, langs); const _registry = new Registry(resolver, themes, langs, options.langAlias); let _lastTheme; function getLanguage(name) { ensureNotDisposed(); const _lang = _registry.getGrammar(typeof name === "string" ? name : name.name); if (!_lang) throw new ShikiError(`Language \`${name}\` not found, you may need to load it first`); return _lang; } function getTheme(name) { if (name === "none") return { bg: "", fg: "", name: "none", settings: [], type: "dark" }; ensureNotDisposed(); const _theme = _registry.getTheme(name); if (!_theme) throw new ShikiError(`Theme \`${name}\` not found, you may need to load it first`); return _theme; } function setTheme(name) { ensureNotDisposed(); const theme = getTheme(name); if (_lastTheme !== name) { _registry.setTheme(theme); _lastTheme = name; } const colorMap = _registry.getColorMap(); return { theme, colorMap }; } function getLoadedThemes() { ensureNotDisposed(); return _registry.getLoadedThemes(); } function getLoadedLanguages() { ensureNotDisposed(); return _registry.getLoadedLanguages(); } function loadLanguageSync(...langs2) { ensureNotDisposed(); _registry.loadLanguages(langs2.flat(1)); } async function loadLanguage(...langs2) { return loadLanguageSync(await resolveLangs(langs2)); } function loadThemeSync(...themes2) { ensureNotDisposed(); for (const theme of themes2.flat(1)) { _registry.loadTheme(theme); } } async function loadTheme(...themes2) { ensureNotDisposed(); return loadThemeSync(await resolveThemes(themes2)); } function ensureNotDisposed() { if (isDisposed) throw new ShikiError("Shiki instance has been disposed"); } function dispose() { if (isDisposed) return; isDisposed = true; _registry.dispose(); instancesCount -= 1; } return { setTheme, getTheme, getLanguage, getLoadedThemes, getLoadedLanguages, loadLanguage, loadLanguageSync, loadTheme, loadThemeSync, dispose, [Symbol.dispose]: dispose }; } async function createShikiInternal(options = {}) { if (options.loadWasm) { warnDeprecated("`loadWasm` option is deprecated. Use `engine: createOnigurumaEngine(loadWasm)` instead."); } const [ themes, langs, engine ] = await Promise.all([ resolveThemes(options.themes || []), resolveLangs(options.langs || []), options.engine || createOnigurumaEngine$1(options.loadWasm || getDefaultWasmLoader()) ]); return createShikiInternalSync({ ...options, loadWasm: undefined, themes, langs, engine }); } function getShikiInternal(options = {}) { warnDeprecated("`getShikiInternal` is deprecated. Use `createShikiInternal` instead."); return createShikiInternal(options); } async function createHighlighterCore(options = {}) { const internal = await createShikiInternal(options); return { getLastGrammarState: (...args) => getLastGrammarState(internal, ...args), codeToTokensBase: (code, options2) => codeToTokensBase(internal, code, options2), codeToTokensWithThemes: (code, options2) => codeToTokensWithThemes(internal, code, options2), codeToTokens: (code, options2) => codeToTokens(internal, code, options2), codeToHast: (code, options2) => codeToHast(internal, code, options2), codeToHtml: (code, options2) => codeToHtml(internal, code, options2), ...internal, getInternalContext: () => internal }; } function createHighlighterCoreSync(options = {}) { const internal = createShikiInternalSync(options); return { getLastGrammarState: (...args) => getLastGrammarState(internal, ...args), codeToTokensBase: (code, options2) => codeToTokensBase(internal, code, options2), codeToTokensWithThemes: (code, options2) => codeToTokensWithThemes(internal, code, options2), codeToTokens: (code, options2) => codeToTokens(internal, code, options2), codeToHast: (code, options2) => codeToHast(internal, code, options2), codeToHtml: (code, options2) => codeToHtml(internal, code, options2), ...internal, getInternalContext: () => internal }; } function makeSingletonHighlighterCore(createHighlighter) { let _shiki; async function getSingletonHighlighterCore2(options = {}) { if (!_shiki) { _shiki = createHighlighter({ ...options, themes: options.themes || [], langs: options.langs || [] }); return _shiki; } else { const s = await _shiki; await Promise.all([ s.loadTheme(...options.themes || []), s.loadLanguage(...options.langs || []) ]); return s; } } return getSingletonHighlighterCore2; } const getSingletonHighlighterCore = /* @__PURE__ */ makeSingletonHighlighterCore(createHighlighterCore); function getHighlighterCore(options = {}) { warnDeprecated("`getHighlighterCore` is deprecated. Use `createHighlighterCore` or `getSingletonHighlighterCore` instead."); return createHighlighterCore(options); } function createdBundledHighlighter(arg1, arg2, arg3) { let bundledLanguages; let bundledThemes; let engine; if (arg2) { warnDeprecated("`createdBundledHighlighter` signature with `bundledLanguages` and `bundledThemes` is deprecated. Use the options object signature instead."); bundledLanguages = arg1; bundledThemes = arg2; engine = () => createOnigurumaEngine(arg3); } else { const options = arg1; bundledLanguages = options.langs; bundledThemes = options.themes; engine = options.engine; } async function createHighlighter(options) { function resolveLang(lang) { if (typeof lang === "string") { if (isSpecialLang(lang)) return []; const bundle = bundledLanguages[lang]; if (!bundle) throw new ShikiError$1(`Language \`${lang}\` is not included in this bundle. You may want to load it from external source.`); return bundle; } return lang; } function resolveTheme(theme) { if (isSpecialTheme(theme)) return "none"; if (typeof theme === "string") { const bundle = bundledThemes[theme]; if (!bundle) throw new ShikiError$1(`Theme \`${theme}\` is not included in this bundle. You may want to load it from external source.`); return bundle; } return theme; } const _themes = (options.themes ?? []).map((i) => resolveTheme(i)); const langs = (options.langs ?? []).map((i) => resolveLang(i)); const core = await createHighlighterCore({ engine: options.engine ?? engine(), ...options, themes: _themes, langs }); return { ...core, loadLanguage(...langs2) { return core.loadLanguage(...langs2.map(resolveLang)); }, loadTheme(...themes) { return core.loadTheme(...themes.map(resolveTheme)); } }; } return createHighlighter; } function makeSingletonHighlighter(createHighlighter) { let _shiki; async function getSingletonHighlighter(options = {}) { if (!_shiki) { _shiki = createHighlighter({ ...options, themes: options.themes || [], langs: options.langs || [] }); return _shiki; } else { const s = await _shiki; await Promise.all([ s.loadTheme(...options.themes || []), s.loadLanguage(...options.langs || []) ]); return s; } } return getSingletonHighlighter; } function createSingletonShorthands(createHighlighter) { const getSingletonHighlighter = makeSingletonHighlighter(createHighlighter); return { getSingletonHighlighter(options) { return getSingletonHighlighter(options); }, async codeToHtml(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: "theme" in options ? [options.theme] : Object.values(options.themes) }); return shiki.codeToHtml(code, options); }, async codeToHast(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: "theme" in options ? [options.theme] : Object.values(options.themes) }); return shiki.codeToHast(code, options); }, async codeToTokens(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: "theme" in options ? [options.theme] : Object.values(options.themes) }); return shiki.codeToTokens(code, options); }, async codeToTokensBase(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: [options.theme] }); return shiki.codeToTokensBase(code, options); }, async codeToTokensWithThemes(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: Object.values(options.themes).filter(Boolean) }); return shiki.codeToTokensWithThemes(code, options); }, async getLastGrammarState(code, options) { const shiki = await getSingletonHighlighter({ langs: [options.lang], themes: [options.theme] }); return shiki.getLastGrammarState(code, options); } }; } function createJavaScriptRegexEngine(options) { warnDeprecated("import `createJavaScriptRegexEngine` from `@shikijs/engine-javascript` or `shiki/engine/javascript` instead"); return createJavaScriptRegexEngine$1(options); } function defaultJavaScriptRegexConstructor(pattern) { warnDeprecated("import `defaultJavaScriptRegexConstructor` from `@shikijs/engine-javascript` or `shiki/engine/javascript` instead"); return defaultJavaScriptRegexConstructor$1(pattern); } function createCssVariablesTheme(options = {}) { const { name = "css-variables", variablePrefix = "--shiki-", fontStyle = true } = options; const variable = (name2) => { if (options.variableDefaults?.[name2]) return `var(${variablePrefix}${name2}, ${options.variableDefaults[name2]})`; return `var(${variablePrefix}${name2})`; }; const theme = { name, type: "dark", colors: { "editor.foreground": variable("foreground"), "editor.background": variable("background"), "terminal.ansiBlack": variable("ansi-black"), "terminal.ansiRed": variable("ansi-red"), "terminal.ansiGreen": variable("ansi-green"), "terminal.ansiYellow": variable("ansi-yellow"), "terminal.ansiBlue": variable("ansi-blue"), "terminal.ansiMagenta": variable("ansi-magenta"), "terminal.ansiCyan": variable("ansi-cyan"), "terminal.ansiWhite": variable("ansi-white"), "terminal.ansiBrightBlack": variable("ansi-bright-black"), "terminal.ansiBrightRed": variable("ansi-bright-red"), "terminal.ansiBrightGreen": variable("ansi-bright-green"), "terminal.ansiBrightYellow": variable("ansi-bright-yellow"), "terminal.ansiBrightBlue": variable("ansi-bright-blue"), "terminal.ansiBrightMagenta": variable("ansi-bright-magenta"), "terminal.ansiBrightCyan": variable("ansi-bright-cyan"), "terminal.ansiBrightWhite": variable("ansi-bright-white") }, tokenColors: [ { scope: [ "keyword.operator.accessor", "meta.group.braces.round.function.arguments", "meta.template.expression", "markup.fenced_code meta.embedded.block" ], settings: { foreground: variable("foreground") } }, { scope: "emphasis", settings: { fontStyle: "italic" } }, { scope: ["strong", "markup.heading.markdown", "markup.bold.markdown"], settings: { fontStyle: "bold" } }, { scope: ["markup.italic.markdown"], settings: { fontStyle: "italic" } }, { scope: "meta.link.inline.markdown", settings: { fontStyle: "underline", foreground: variable("token-link") } }, { scope: ["string", "markup.fenced_code", "markup.inline"], settings: { foreground: variable("token-string") } }, { scope: ["comment", "string.quoted.docstring.multi"], settings: { foreground: variable("token-comment") } }, { scope: [ "constant.numeric", "constant.language", "constant.other.placeholder", "constant.character.format.placeholder", "variable.language.this", "variable.other.object", "variable.other.class", "variable.other.constant", "meta.property-name", "meta.property-value", "support" ], settings: { foreground: variable("token-constant") } }, { scope: [ "keyword", "storage.modifier", "storage.type", "storage.control.clojure", "entity.name.function.clojure", "entity.name.tag.yaml", "support.function.node", "support.type.property-name.json", "punctuation.separator.key-value", "punctuation.definition.template-expression" ], settings: { foreground: variable("token-keyword") } }, { scope: "variable.parameter.function", settings: { foreground: variable("token-parameter") } }, { scope: [ "support.function", "entity.name.type", "entity.other.inherited-class", "meta.function-call", "meta.instance.constructor", "entity.other.attribute-name", "entity.name.function", "constant.keyword.clojure" ], settings: { foreground: variable("token-function") } }, { scope: [ "entity.name.tag", "string.quoted", "string.regexp", "string.interpolated", "string.template", "string.unquoted.plain.out.yaml", "keyword.other.template" ], settings: { foreground: variable("token-string-expression") } }, { scope: [ "punctuation.definition.arguments", "punctuation.definition.dict", "punctuation.separator", "meta.function-call.arguments" ], settings: { foreground: variable("token-punctuation") } }, { // [Custom] Markdown links scope: [ "markup.underline.link", "punctuation.definition.metadata.markdown" ], settings: { foreground: variable("token-link") } }, { // [Custom] Markdown list scope: ["beginning.punctuation.definition.list.markdown"], settings: { foreground: variable("token-string") } }, { // [Custom] Markdown punctuation definition brackets scope: [ "punctuation.definition.string.begin.markdown", "punctuation.definition.string.end.markdown", "string.other.link.title.markdown", "string.other.link.description.markdown" ], settings: { foreground: variable("token-keyword") } }, { // [Custom] Diff scope: [ "markup.inserted", "meta.diff.header.to-file", "punctuation.definition.inserted" ], settings: { foreground: variable("token-inserted") } }, { scope: [ "markup.deleted", "meta.diff.header.from-file", "punctuation.definition.deleted" ], settings: { foreground: variable("token-deleted") } }, { scope: [ "markup.changed", "punctuation.definition.changed" ], settings: { foreground: variable("token-changed") } } ] }; if (!fontStyle) { theme.tokenColors = theme.tokenColors?.map((tokenColor) => { if (tokenColor.settings?.fontStyle) delete tokenColor.settings.fontStyle; return tokenColor; }); } return theme; } export { addClassToHast, applyColorReplacements, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createCssVariablesTheme, createHighlighterCore, createHighlighterCoreSync, createJavaScriptRegexEngine, createOnigurumaEngine, createPositionConverter, createShikiInternal, createShikiInternalSync, createSingletonShorthands, createWasmOnigEngine, createdBundledHighlighter, defaultJavaScriptRegexConstructor, getHighlighterCore, getShikiInternal, getSingletonHighlighterCore, getTokenStyleObject, isNoneTheme, isPlainLang, isSpecialLang, isSpecialTheme, loadWasm, makeSingletonHighlighter, makeSingletonHighlighterCore, normalizeGetter, normalizeTheme, resolveColorReplacements, splitLines, splitToken, splitTokens, stringifyTokenStyle, toArray, tokenizeAnsiWithTheme, tokenizeWithTheme, tokensToHast, transformerDecorations, warnDeprecated };