11import { ExpressiveCodeEngine , ExpressiveCodeTheme } from '@expressive-code/core' ;
22import type ShikiPlugin from 'src/main' ;
3- import { bundledLanguages , createHighlighter , type DynamicImportLanguageRegistration , type LanguageRegistration , type Highlighter } from 'shiki/index.mjs' ;
3+ import {
4+ bundledLanguages ,
5+ createHighlighter ,
6+ type DynamicImportLanguageRegistration ,
7+ type LanguageRegistration ,
8+ type Highlighter ,
9+ type TokensResult ,
10+ type BundledLanguage ,
11+ type ThemedToken ,
12+ } from 'shiki/index.mjs' ;
413import { ThemeMapper } from 'src/themes/ThemeMapper' ;
514import { pluginShiki } from '@expressive-code/plugin-shiki' ;
615import { pluginCollapsibleSections } from '@expressive-code/plugin-collapsible-sections' ;
@@ -178,6 +187,20 @@ export class CodeHighlighter {
178187 return this . plugin . loadedSettings . theme . endsWith ( '.json' ) ;
179188 }
180189
190+ /**
191+ * Returns a list of languages registrations that need to be loaded into Shiki and EC.
192+ */
193+ getLoadedLanguageRegistrations ( ) : ( DynamicImportLanguageRegistration | LanguageRegistration ) [ ] {
194+ return [ ...Object . values ( bundledLanguages ) , ...this . customLanguages ] ;
195+ }
196+
197+ /**
198+ * All languages that are safe to use with Obsidian's `registerMarkdownCodeBlockProcessor`.
199+ */
200+ obsidianSafeLanguageNames ( ) : string [ ] {
201+ return this . loadedLanguages . filter ( lang => ! languageNameBlacklist . has ( lang ) ) ;
202+ }
203+
181204 /**
182205 * Highlights code with EC and renders it to the passed container element.
183206 */
@@ -191,11 +214,36 @@ export class CodeHighlighter {
191214 container . innerHTML = toHtml ( this . themeMapper . fixAST ( result . renderedGroupAst ) ) ;
192215 }
193216
194- getLoadedLanguageRegistrations ( ) : ( DynamicImportLanguageRegistration | LanguageRegistration ) [ ] {
195- return [ ...Object . values ( bundledLanguages ) , ...this . customLanguages ] ;
217+ getHighlightTokens ( code : string , lang : string ) : TokensResult | undefined {
218+ if ( ! this . obsidianSafeLanguageNames ( ) . includes ( lang ) ) {
219+ return undefined ;
220+ }
221+
222+ return this . shiki . codeToTokens ( code , {
223+ lang : lang as BundledLanguage ,
224+ theme : this . plugin . settings . theme ,
225+ } ) ;
196226 }
197227
198- obsidianSafeLanguageNames ( ) : string [ ] {
199- return this . loadedLanguages . filter ( lang => ! languageNameBlacklist . has ( lang ) ) ;
228+ tokenToSpan ( token : ThemedToken , parent : HTMLElement ) : void {
229+ const tokenStyle = this . getTokenStyle ( token ) ;
230+ parent . createSpan ( {
231+ text : token . content ,
232+ cls : tokenStyle . classes . join ( ' ' ) ,
233+ attr : { style : tokenStyle . style } ,
234+ } ) ;
235+ }
236+
237+ getTokenStyle ( token : ThemedToken ) : { style : string ; classes : string [ ] } {
238+ const fontStyle = token . fontStyle ?? 0 ;
239+
240+ return {
241+ style : `color: ${ token . color } ` ,
242+ classes : [
243+ ( fontStyle & 1 ) !== 0 ? 'shiki-italic' : undefined ,
244+ ( fontStyle & 2 ) !== 0 ? 'shiki-bold' : undefined ,
245+ ( fontStyle & 4 ) !== 0 ? 'shiki-ul' : undefined ,
246+ ] . filter ( Boolean ) as string [ ] ,
247+ } ;
200248 }
201249}
0 commit comments