Hexo 处理的代码块会被包裹在 figure table tbody tr > td.code pre 中,每一行代码又被 span 包裹,如果需要加入对 Typst 的支持,需要将所有的代码重新提取出来,处理后之后再填入,有两种方法可以选择:
前端修改:在 html 页面中读取代码块元素,提取代码处理后再填入 (1)  标签插件(推荐 ) :在 hexo 生成的过程中使用标签插件 (2)   处理前端修改  此方法可能需要刷新才能正常显示 此方法会将所有的 plaintext 识别为 typst,可以通过在第一行加一行说明语言来处理
引入 js 文件  1 2 3 4 5 <script  crossorigin ="anonymous"  src ="https://foolishfox.cn/js/hl.js" > </script > <script    id ="script-main"    src ="https://cdn.jsdelivr.net/npm/@myriaddreamin/highlighter-typst/dist/cjs/contrib/hljs/typst.bundle.js"  > </script > 
注册 Typst 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 const  run  = ( ) => {    $typst$parserModule.then (() =>  {         hljs.registerLanguage (             'typst' ,             window .hljsTypst ({                 codeBlockDefaultLanguage : 'typst' ,             }),         );         hljs.configure ({             classPrefix : ''           });     }).then (() =>  {         document .querySelectorAll ('figure table tbody tr > td.code pre' ).forEach (el  =>  {             if  (!el.getAttribute ('data-highlighted' )) {                 var  pre = document .createElement ("pre" );                 var  lang = el.parentNode .parentNode .parentNode .parentNode .parentNode .classList [1 ];                 var  code = "" ;                 for  (i = 0 ; i < el.childElementCount ; i++){                     ch = el.children [i];                     if  (ch.tagName  == "SPAN" ) code += ch.textContent ;                     if  (ch.tagName  == "BR" ) code += "\n" ;                 }                 if  (lang == "plaintext" ) {                     lang = "typst" ;                 }                 if  (lang != "plaintext" ) {                     el.innerHTML  = hljs.highlight (code, {language : lang}).value                  }             }         });     }); } run ();
标签插件  查看 Hexo 原生处理代码块的逻辑 (4)  :
register plugins/tag/index.ts 12 13 14 15 const  code = require ('./code' )(ctx);tag.register ('code' , code, true ); tag.register ('codeblock' , code, true ); 
在 code 模块中,先对传入的参数进行了解析,然后再调用 hexo-utils 的 highlight 进行渲染:
code plugins/tag/code.ts 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 function  parseArgs (args: string[] ): HighlightOptions  {  ......   return  {     lang,     language_attr,     firstLine,     caption,     line_number,     line_threshold,     mark,     wrap   }; } module .exports  = ctx  =>  function  codeTag (args, content ) {    ......     const  options = parseArgs (args);     options.lines_length  = content.split ('\n' ).length ;     content = ctx.extend .highlight .exec (ctx.config .syntax_highlighter , {         context : ctx,         args : [content, options]     });     return  content.replace (/{/g , '{' ).replace (/}/g , '}' ); }; 
所以我们可以在返回 content 之前对其进行处理,处理的逻辑与前一种方法是类似的,首先导入所需要的模块:
import typst.js 1 2 3 const  hljs = require ('highlight.js' );const  highlight = require ('hexo-util' ).highlight ;const  typstBunlde = require ('./typst.bundle' );
然后获取 highlight 处理过后的代码块:
highlight process typst.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const  codeTypst  = (args, content ) => {    const  options = parseArgs (args);     options.lines_length  = content.split ('\n' ).length ;     const  line_threshold = options.line_threshold  || 0 ;     const  shouldUseLineNumbers = options.line_number ;     const  surpassesLineThreshold = options.lines_length  > line_threshold;     const  gutter = shouldUseLineNumbers && surpassesLineThreshold;     const  hljsOptions = {         caption : options.caption ,         firstLine : options.firstLine ,         gutter,         mark : options.mark ,     };     var  contentHljs = highlight (content, hljsOptions);     contentHljs = contentHljs.replace (/{/g , '{' ).replace (/}/g , '}' );     ...... } 
然后注册 Typst 语言,并提取代码进行处理:
extract and process typst.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const  codeTypst  = (args, content ) => {    ......     return  typstBunlde.parserModule .then (() =>  {         hljs.registerLanguage (             'typst' ,             typstBunlde.hljsTypst ({                 codeBlockDefaultLanguage : 'typst' ,             }),         )     }).then (() =>  {         var  re = /<td class="code"><pre>(.+)<\/pre><\/td>/i ;         var  code = hljs.highlight (content, {language : 'typst' }).value ;         contentHljs = contentHljs.replace ("highlight plaintext" , "highlight typst" )         return  contentHljs.replace (re, `<td class="code"><pre>${code} </pre></td>` );     }); } 
最后在 Hexo 中注册这个标签插件,由于注册 Typst 语言并处理的过程是异步的,所以这里也要开启异步选项:
register with async typst.js 1 hexo.extend .tag .register ('typst' , codeTypst, {ends : true , async : true }); 
示例  使用方法  预览  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 {% typst %} #import "@preview/tablex:0.0.6": tablex, rowspanx, colspanx, hlinex, vlinex #let three-line-table(columns, headers, contents, caption, lang: "en",rows: auto) = {figure(   tablex(     columns: columns,     rows: rows,     align: center + horizon,     auto-lines: false,     repeat-header: true,     hlinex(stroke: 1.5pt),     ..headers,     hlinex(stroke: 0.75pt),     ..contents,     hlinex(stroke: 1.5pt),   ),   kind: table,   supplement: [#if (lang == "en") {"Table"} else {"表"}],   caption: caption, )} {% endtypst %} 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # import  "@preview/tablex:0.0.6" :  tablex ,  rowspanx ,  colspanx ,  hlinex ,  vlinex 
# let  three-line-table ( columns ,  headers ,  contents ,  caption ,  lang :  "en" , rows :  auto )  =  { figure ( 
  tablex ( 
    columns :  columns , 
    rows :  rows , 
    align :  center  +  horizon , 
    auto-lines :  false , 
    repeat-header :  true , 
    hlinex ( stroke :  1.5pt ) , 
    .. headers , 
    hlinex ( stroke :  0.75pt ) , 
    .. contents , 
    hlinex ( stroke :  1.5pt ) , 
  ) , 
  kind :  table , 
  supplement :  [ # if  ( lang  ==  "en" )  { "Table" }  else  { "表" } ] , 
  caption :  caption , 
) } 
参考资料  在 Hugo 中为 Typst 配置语法高亮(PaperMod 主题) 标签插件(Tag) highlighter 代码高亮