1212 * @returns The processed string with LaTeX replaced by placeholders.
1313 */
1414export function maskInlineLaTeX ( content : string , latexExpressions : string [ ] ) : string {
15- if ( content . indexOf ( '$' ) == - 1 ) {
15+ if ( ! content . includes ( '$' ) ) {
1616 return content ;
1717 }
1818 return content
@@ -21,56 +21,67 @@ export function maskInlineLaTeX(content: string, latexExpressions: string[]): st
2121 if ( line . indexOf ( '$' ) == - 1 ) {
2222 return line ;
2323 }
24- let result = '' ;
25- let index = 0 ;
26- while ( index < line . length ) {
27- const openIndex = line . indexOf ( '$' , index ) ;
28- if ( openIndex == - 1 ) {
29- result += line . slice ( index ) ;
24+
25+ let processedLine = '' ;
26+ let currentPosition = 0 ;
27+
28+ while ( currentPosition < line . length ) {
29+ const openDollarIndex = line . indexOf ( '$' , currentPosition ) ;
30+
31+ if ( openDollarIndex == - 1 ) {
32+ processedLine += line . slice ( currentPosition ) ;
3033 break ;
3134 }
3235
3336 // Is there a next $-sign?
34- const nextIndex = line . indexOf ( '$' , openIndex + 1 ) ;
35- if ( nextIndex == - 1 ) {
36- result += line . slice ( index ) ;
37+ const closeDollarIndex = line . indexOf ( '$' , openDollarIndex + 1 ) ;
38+
39+ if ( closeDollarIndex == - 1 ) {
40+ processedLine += line . slice ( currentPosition ) ;
3741 break ;
3842 }
3943
40- const beforeOpenChar = openIndex > 0 ? line [ openIndex - 1 ] : '' ;
41- const afterOpenChar = line [ openIndex + 1 ] ;
42- const beforeCloseChar = openIndex + 1 < nextIndex ? line [ nextIndex - 1 ] : '' ;
43- const afterCloseChar = nextIndex + 1 < line . length ? line [ nextIndex + 1 ] : '' ;
44- let cont = false ;
45- if ( nextIndex == index + 1 ) {
46- // no content
47- cont = true ;
44+ const charBeforeOpen = openDollarIndex > 0 ? line [ openDollarIndex - 1 ] : '' ;
45+ const charAfterOpen = line [ openDollarIndex + 1 ] ;
46+ const charBeforeClose = openDollarIndex + 1 < closeDollarIndex ? line [ closeDollarIndex - 1 ] : '' ;
47+ const charAfterClose = closeDollarIndex + 1 < line . length ? line [ closeDollarIndex + 1 ] : '' ;
48+
49+ let shouldSkipAsNonLatex = false ;
50+
51+ if ( closeDollarIndex == currentPosition + 1 ) {
52+ // No content
53+ shouldSkipAsNonLatex = true ;
4854 }
49- if ( / [ A - Z a - z 0 - 9 _ $ - ] / . test ( beforeOpenChar ) ) {
50- // character, digit, $, _ or - before first '$', no TeX.
51- cont = true ;
55+
56+ if ( / [ A - Z a - z 0 - 9 _ $ - ] / . test ( charBeforeOpen ) ) {
57+ // Character, digit, $, _ or - before first '$', no TeX.
58+ shouldSkipAsNonLatex = true ;
5259 }
60+
5361 if (
54- / [ 0 - 9 ] / . test ( afterOpenChar ) &&
55- ( / [ A - Z a - z 0 - 9 _ $ - ] / . test ( afterCloseChar ) || ' ' == beforeCloseChar )
62+ / [ 0 - 9 ] / . test ( charAfterOpen ) &&
63+ ( / [ A - Z a - z 0 - 9 _ $ - ] / . test ( charAfterClose ) || ' ' == charBeforeClose )
5664 ) {
5765 // First $ seems to belong to an amount.
58- cont = true ;
66+ shouldSkipAsNonLatex = true ;
5967 }
60- if ( cont ) {
61- result += line . slice ( index , openIndex + 1 ) ;
62- index = openIndex + 1 ;
68+
69+ if ( shouldSkipAsNonLatex ) {
70+ processedLine += line . slice ( currentPosition , openDollarIndex + 1 ) ;
71+ currentPosition = openDollarIndex + 1 ;
72+
6373 continue ;
6474 }
6575
6676 // Treat as LaTeX
67- result += line . slice ( index , openIndex ) ;
68- const latexContent = line . slice ( openIndex , nextIndex + 1 ) ;
77+ processedLine += line . slice ( currentPosition , openDollarIndex ) ;
78+ const latexContent = line . slice ( openDollarIndex , closeDollarIndex + 1 ) ;
6979 latexExpressions . push ( latexContent ) ;
70- result += `<<LATEX_${ latexExpressions . length - 1 } >>` ;
71- index = nextIndex + 1 ;
80+ processedLine += `<<LATEX_${ latexExpressions . length - 1 } >>` ;
81+ currentPosition = closeDollarIndex + 1 ;
7282 }
73- return result ;
83+
84+ return processedLine ;
7485 } )
7586 . join ( '\n' ) ;
7687}
@@ -81,6 +92,7 @@ function escapeBrackets(text: string): string {
8192 // `Definitions\\(also called macros)` (title of chapter 20 in The TeXbook)
8293 // or `\\[4pt]`.
8394 const pattern = / ( ` ` ` [ \S \s ] * ?` ` ` | ` .* ?` ) | (?< ! \\ ) \\ \[ ( [ \S \s ] * ?[ ^ \\ ] ) \\ ] | (?< ! \\ ) \\ \( ( .* ?) \\ \) / g;
95+
8496 return text . replace (
8597 pattern ,
8698 (
@@ -96,6 +108,7 @@ function escapeBrackets(text: string): string {
96108 } else if ( roundBracket != null ) {
97109 return `$${ roundBracket } $` ;
98110 }
111+
99112 return match ;
100113 }
101114 ) ;
@@ -134,8 +147,10 @@ const codeBlockRegex = /(```[\s\S]*?```|`[^`\n]+`)/g;
134147export function preprocessLaTeX ( content : string ) : string {
135148 // Step 1: Protect code blocks
136149 const codeBlocks : string [ ] = [ ] ;
150+
137151 content = content . replace ( codeBlockRegex , ( match ) => {
138152 codeBlocks . push ( match ) ;
153+
139154 return `<<CODE_BLOCK_${ codeBlocks . length - 1 } >>` ;
140155 } ) ;
141156
@@ -150,13 +165,15 @@ export function preprocessLaTeX(content: string): string {
150165 }
151166 const hasSuffix = / \S / . test ( group3 ) ;
152167 let optBreak ;
168+
153169 if ( hasSuffix ) {
154170 latexExpressions . push ( `\\(${ group2 . trim ( ) } \\)` ) ; // Convert into inline.
155171 optBreak = '' ;
156172 } else {
157173 latexExpressions . push ( `\\[${ group2 } \\]` ) ;
158174 optBreak = '\n' ;
159175 }
176+
160177 return `${ group1 } ${ optBreak } <<LATEX_${ latexExpressions . length - 1 } >>${ optBreak } ${ group3 } ` ;
161178 } ) ;
162179
@@ -165,6 +182,7 @@ export function preprocessLaTeX(content: string): string {
165182 / ( \$ \$ [ \s \S ] * ?\$ \$ | (?< ! \\ ) \\ \[ [ \s \S ] * ?\\ \] | (?< ! \\ ) \\ \( .* ?\\ \) ) / g,
166183 ( match ) => {
167184 latexExpressions . push ( match ) ;
185+
168186 return `<<LATEX_${ latexExpressions . length - 1 } >>` ;
169187 }
170188 ) ;
@@ -188,6 +206,7 @@ export function preprocessLaTeX(content: string): string {
188206
189207 // Step 6: Apply additional escaping functions (brackets and mhchem)
190208 content = escapeBrackets ( content ) ;
209+
191210 if ( content . includes ( '\\ce{' ) || content . includes ( '\\pu{' ) ) {
192211 content = escapeMhchem ( content ) ;
193212 }
0 commit comments