@@ -4,6 +4,7 @@ import {type Patch, type PatchItem, getPatch} from "fast-array-diff";
4
4
import equal from "fast-deep-equal" ;
5
5
import matter from "gray-matter" ;
6
6
import hljs from "highlight.js" ;
7
+ import katex from "katex" ;
7
8
import { parseHTML } from "linkedom" ;
8
9
import MarkdownIt from "markdown-it" ;
9
10
import { type RuleCore } from "markdown-it/lib/parser_core.js" ;
@@ -79,18 +80,32 @@ function uniqueCodeId(context: ParseContext, content: string): string {
79
80
return id ;
80
81
}
81
82
82
- function getLiveSource ( content , language , option ) {
83
+ function getLiveSource ( content , language , option ) : { source ?: string ; html ?: string } {
83
84
return option === "no-run"
84
- ? undefined
85
+ ? { }
85
86
: language === "js"
86
- ? content
87
+ ? { source : content }
87
88
: language === "tex"
88
- ? transpileTag ( content , "tex.block" , true )
89
+ ? maybeStaticTeX ( content , true )
89
90
: language === "dot"
90
- ? transpileTag ( content , "dot" , false )
91
+ ? { source : transpileTag ( content , "dot" , false ) }
91
92
: language === "mermaid"
92
- ? transpileTag ( content , "await mermaid" , false )
93
- : undefined ;
93
+ ? { source : transpileTag ( content , "await mermaid" , false ) }
94
+ : { } ;
95
+ }
96
+
97
+ function maybeStaticTeX ( content , displayMode ) {
98
+ try {
99
+ // TODO smarter detection of ${} contents
100
+ // TODO smarter insertion of the TeX stylesheet
101
+ return {
102
+ html :
103
+ katex . renderToString ( content , { displayMode} ) +
104
+ `<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/katex/dist/katex.min.css">`
105
+ } ;
106
+ } catch {
107
+ return { source : transpileTag ( content , displayMode ? "tex.block" : "tex" , true ) } ;
108
+ }
94
109
}
95
110
96
111
function makeFenceRenderer ( root : string , baseRenderer : RenderRule , sourcePath : string ) : RenderRule {
@@ -99,7 +114,7 @@ function makeFenceRenderer(root: string, baseRenderer: RenderRule, sourcePath: s
99
114
const [ language , option ] = token . info . split ( " " ) ;
100
115
let result = "" ;
101
116
let count = 0 ;
102
- const source = getLiveSource ( token . content , language , option ) ;
117
+ const { source, html } = getLiveSource ( token . content , language , option ) ;
103
118
if ( source != null ) {
104
119
const id = uniqueCodeId ( context , token . content ) ;
105
120
const sourceLine = context . startLine + context . currentLine ;
@@ -115,6 +130,7 @@ function makeFenceRenderer(root: string, baseRenderer: RenderRule, sourcePath: s
115
130
result += `<div id="cell-${ id } " class="observablehq observablehq--block"></div>\n` ;
116
131
count ++ ;
117
132
}
133
+ if ( html !== undefined ) result += html ;
118
134
if ( source == null || option === "show" ) {
119
135
result += baseRenderer ( tokens , idx , options , context , self ) ;
120
136
count ++ ;
@@ -258,6 +274,13 @@ function makePlaceholderRenderer(root: string, sourcePath: string): RenderRule {
258
274
return ( tokens , idx , options , context : ParseContext ) => {
259
275
const id = uniqueCodeId ( context , tokens [ idx ] . content ) ;
260
276
const token = tokens [ idx ] ;
277
+
278
+ // inline TeX?
279
+ if ( token . content . match ( / ^ t e x [ ` ] / ) ) {
280
+ const { html} = maybeStaticTeX ( token . content . slice ( 4 , - 1 ) , false ) ;
281
+ if ( html !== undefined ) return `<span id="cell-${ id } ">${ html } </span>` ;
282
+ }
283
+
261
284
const transpile = transpileJavaScript ( token . content , {
262
285
id,
263
286
root,
0 commit comments