diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 5dd3e37e7..c83b8f818 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,8 +16,8 @@ export { codeToTokens } from './highlight/code-to-tokens' export { tokenizeAnsiWithTheme } from './highlight/code-to-tokens-ansi' export { codeToTokensBase, tokenizeWithTheme } from './highlight/code-to-tokens-base' export { codeToTokensWithThemes } from './highlight/code-to-tokens-themes' - export { normalizeTheme } from './textmate/normalize-theme' +export * from './theme-css-variables' export { transformerDecorations } from './transformer-decorations' // Utils and Misc diff --git a/packages/core/src/theme-css-variables.ts b/packages/core/src/theme-css-variables.ts new file mode 100644 index 000000000..1e27fbd99 --- /dev/null +++ b/packages/core/src/theme-css-variables.ts @@ -0,0 +1,276 @@ +import type { ThemeRegistration } from '@shikijs/types' + +export interface CssVariablesThemeOptions { + /** + * Theme name. Need to unique if multiple css variables themes are created + * + * @default 'css-variables' + */ + name?: string + + /** + * Prefix for css variables + * + * @default '--shiki-' + */ + variablePrefix?: string + + /** + * Default value for css variables, the key is without the prefix + * + * @example `{ 'token-comment': '#888' }` will generate `var(--shiki-token-comment, #888)` for comments + */ + variableDefaults?: Record + + /** + * Enable font style + * + * @default true + */ + fontStyle?: boolean +} + +/** + * A factory function to create a css-variable-based theme + * + * @see https://shiki.style/guide/theme-colors#css-variables-theme + */ +export function createCssVariablesTheme(options: CssVariablesThemeOptions = {}): ThemeRegistration { + const { + name = 'css-variables', + variablePrefix = '--shiki-', + fontStyle = true, + } = options + + const variable = (name: string): string => { + if (options.variableDefaults?.[name]) + return `var(${variablePrefix}${name}, ${options.variableDefaults[name]})` + return `var(${variablePrefix}${name})` + } + + const theme: ThemeRegistration = { + 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) + // @ts-expect-error force delete readonly property + delete tokenColor.settings.fontStyle + return tokenColor + }) + } + + return theme +} diff --git a/packages/shiki/src/core.ts b/packages/shiki/src/core.ts index 47350ec26..8b0bfba2e 100644 --- a/packages/shiki/src/core.ts +++ b/packages/shiki/src/core.ts @@ -1,4 +1 @@ -export type { CssVariablesThemeOptions } from './theme-css-variables' - -export { createCssVariablesTheme } from './theme-css-variables' export * from '@shikijs/core' diff --git a/packages/shiki/src/theme-css-variables.ts b/packages/shiki/src/theme-css-variables.ts index 1e27fbd99..ae57356d9 100644 --- a/packages/shiki/src/theme-css-variables.ts +++ b/packages/shiki/src/theme-css-variables.ts @@ -1,276 +1,6 @@ -import type { ThemeRegistration } from '@shikijs/types' +import { warnDeprecated } from '@shikijs/core' -export interface CssVariablesThemeOptions { - /** - * Theme name. Need to unique if multiple css variables themes are created - * - * @default 'css-variables' - */ - name?: string +export { createCssVariablesTheme } from './core' +export type { CssVariablesThemeOptions } from './core' - /** - * Prefix for css variables - * - * @default '--shiki-' - */ - variablePrefix?: string - - /** - * Default value for css variables, the key is without the prefix - * - * @example `{ 'token-comment': '#888' }` will generate `var(--shiki-token-comment, #888)` for comments - */ - variableDefaults?: Record - - /** - * Enable font style - * - * @default true - */ - fontStyle?: boolean -} - -/** - * A factory function to create a css-variable-based theme - * - * @see https://shiki.style/guide/theme-colors#css-variables-theme - */ -export function createCssVariablesTheme(options: CssVariablesThemeOptions = {}): ThemeRegistration { - const { - name = 'css-variables', - variablePrefix = '--shiki-', - fontStyle = true, - } = options - - const variable = (name: string): string => { - if (options.variableDefaults?.[name]) - return `var(${variablePrefix}${name}, ${options.variableDefaults[name]})` - return `var(${variablePrefix}${name})` - } - - const theme: ThemeRegistration = { - 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) - // @ts-expect-error force delete readonly property - delete tokenColor.settings.fontStyle - return tokenColor - }) - } - - return theme -} +warnDeprecated('`shiki/theme-css-variables` entry point is deprecated. Use `shiki/core` instead.')