@@ -23,8 +23,11 @@ function isSafeBoundary(character_code, delimiter_code, md) {
23
23
return false ;
24
24
}
25
25
26
- let inlineMath = delimiter => ( state , silent ) => {
27
- let delimiter_code = delimiter . charCodeAt ( 0 ) ;
26
+ let inlineMath = ( startDelimiter , endDelimiter ) => ( state , silent ) => {
27
+ // DH Hack for now
28
+ // TODO: support multiple-char delimiters
29
+ let delimiter_code = startDelimiter . charCodeAt ( 0 ) ;
30
+ let end_delimiter_code = endDelimiter . charCodeAt ( 0 ) ;
28
31
let pos = state . pos ,
29
32
posMax = state . posMax ;
30
33
@@ -37,7 +40,7 @@ let inlineMath = delimiter => (state, silent) => {
37
40
}
38
41
39
42
// too short
40
- if ( state . src . charCodeAt ( pos + 1 ) === delimiter_code ) {
43
+ if ( state . src . charCodeAt ( pos + 1 ) === end_delimiter_code ) {
41
44
return false ;
42
45
}
43
46
@@ -51,7 +54,7 @@ let inlineMath = delimiter => (state, silent) => {
51
54
let found ;
52
55
for ( let i = pos + 1 ; i < posMax ; i ++ ) {
53
56
let code = state . src . charCodeAt ( i ) ;
54
- if ( code === delimiter_code && state . src . charCodeAt ( i - 1 ) !== 92 /* \ */ ) {
57
+ if ( code === end_delimiter_code && state . src . charCodeAt ( i - 1 ) !== 92 /* \ */ ) {
55
58
found = i ;
56
59
break ;
57
60
}
@@ -63,7 +66,7 @@ let inlineMath = delimiter => (state, silent) => {
63
66
64
67
if ( found + 1 <= posMax ) {
65
68
let next = state . src . charCodeAt ( found + 1 ) ;
66
- if ( next && ! isSafeBoundary ( next , delimiter_code , state . md ) ) {
69
+ if ( next && ! isSafeBoundary ( next , end_delimiter_code , state . md ) ) {
67
70
return false ;
68
71
}
69
72
}
@@ -72,7 +75,7 @@ let inlineMath = delimiter => (state, silent) => {
72
75
let token = state . push ( "html_raw" , "" , 0 ) ;
73
76
74
77
const escaped = state . md . utils . escapeHtml ( data ) ;
75
- let math_class = delimiter_code === 37 /* % */ ? "'asciimath'" : "'math'" ;
78
+ let math_class = startDelimiter === endDelimiter === '%' ? "'asciimath'" : "'math'" ;
76
79
token . content = `<span class=${ math_class } >${ escaped } </span>` ;
77
80
state . pos = found + 1 ;
78
81
return true ;
@@ -83,8 +86,8 @@ function isBlockMarker(state, start, max, md, blockMarker) {
83
86
if ( ! state . src . startsWith ( blockMarker , start ) ) {
84
87
return false ;
85
88
}
86
-
87
- // ensure we only have spaces and newline after blockmarker
89
+
90
+ // ensure we only have spaces and newlines after block math marker
88
91
for ( let i = start + blockMarker . length ; i < max ; i ++ ) {
89
92
if ( ! md . utils . isSpace ( state . src . charCodeAt ( i ) ) ) {
90
93
return false ;
@@ -94,11 +97,26 @@ function isBlockMarker(state, start, max, md, blockMarker) {
94
97
return true ;
95
98
}
96
99
97
- let blockMath = blockMarker => ( state , startLine , endLine , silent ) => {
100
+ let blockMath = ( startBlockMathMarker , endBlockMathMarker ) => ( state , startLine , endLine , silent ) => {
98
101
let start = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
99
102
max = state . eMarks [ startLine ] ;
100
103
101
- if ( ! isBlockMarker ( state , start , max , state . md , blockMarker ) ) {
104
+ let startBlockMarker = startBlockMathMarker ;
105
+ let endBlockMarker = endBlockMathMarker ;
106
+
107
+ // Special processing for /\begin{[a-z]+}/
108
+ if ( startBlockMarker instanceof RegExp ) {
109
+ let substr = state . src . substring ( start , max ) ;
110
+ let match = substr . match ( startBlockMarker ) ;
111
+ if ( ! match ) {
112
+ return false ;
113
+ }
114
+ let mathEnv = match [ 1 ] ;
115
+ startBlockMarker = `\\begin{${ mathEnv } }` ;
116
+ endBlockMarker = `\\end{${ mathEnv } }` ;
117
+ }
118
+
119
+ if ( ! isBlockMarker ( state , start , max , state . md , startBlockMarker ) ) {
102
120
return false ;
103
121
}
104
122
@@ -122,7 +140,7 @@ let blockMath = blockMarker => (state, startLine, endLine, silent) => {
122
140
state . bMarks [ nextLine ] + state . tShift [ nextLine ] ,
123
141
state . eMarks [ nextLine ] ,
124
142
state . md ,
125
- blockMarker . replace ( '\\begin{' , '\\end{' )
143
+ endBlockMarker
126
144
)
127
145
) {
128
146
closed = true ;
@@ -132,12 +150,12 @@ let blockMath = blockMarker => (state, startLine, endLine, silent) => {
132
150
133
151
let token = state . push ( "html_raw" , "" , 0 ) ;
134
152
135
- // Blockmarker starting with \begin{ end ending with '\end{'
153
+ // Math environment blockmarkers ' \begin{}' and '\end{} '
136
154
// needs to be passed to the TeX engine
137
- let endContent = blockMarker . startsWith ( '\\begin {' ) || ! closed ?
155
+ let endContent = endBlockMarker . startsWith ( '\\end {' ) || ! closed ?
138
156
state . eMarks [ nextLine ] : state . eMarks [ nextLine - 1 ] ;
139
157
140
- let startContent = blockMarker . startsWith ( '\\begin{' ) ?
158
+ let startContent = startBlockMarker . startsWith ( '\\begin{' ) ?
141
159
state . bMarks [ startLine ] : state . bMarks [ startLine + 1 ] + state . tShift [ startLine + 1 ] ;
142
160
143
161
let content = state . src . slice ( startContent , endContent ) ;
@@ -155,35 +173,52 @@ export function setup(helper) {
155
173
return ;
156
174
}
157
175
158
- let enable_asciimath ;
176
+ let enableAsciiMath , enableMathEnvs ;
159
177
let inlineDelimiters , blockDelimiters ;
160
178
helper . registerOptions ( ( opts , siteSettings ) => {
161
179
opts . features . math = siteSettings . discourse_math_enabled ;
162
- enable_asciimath = siteSettings . discourse_math_enable_asciimath ;
180
+ enableAsciiMath = siteSettings . discourse_math_enable_asciimath ;
181
+ enableMathEnvs = siteSettings . discourse_math_process_tex_environments ;
163
182
inlineDelimiters = siteSettings . discourse_math_inline_delimiters ;
164
183
blockDelimiters = siteSettings . discourse_math_block_delimiters ;
165
184
} ) ;
166
185
167
186
helper . registerPlugin ( md => {
168
- if ( enable_asciimath ) {
169
- md . inline . ruler . after ( "escape" , "asciimath" , inlineMath ( '%' ) ) ;
170
- }
171
- if ( inlineDelimiters ) {
172
- inlineDelimiters . split ( '|' ) . forEach ( delim => {
173
- // We expect only one character
174
- // for inline math delimiter
175
- let d = delim . trim ( ) ;
176
- if ( d . length !== 1 ) return ;
177
- md . inline . ruler . after ( "escape" , "math" , inlineMath ( d ) ) ;
178
- } ) ;
187
+ if ( enableAsciiMath ) {
188
+ md . inline . ruler . after ( "escape" , "asciimath" , inlineMath ( '%' , '%' ) ) ;
179
189
}
180
- if ( blockDelimiters ) {
181
- blockDelimiters . split ( '|' ) . forEach ( delim => {
182
- let d = delim . trim ( ) ;
183
- md . block . ruler . after ( "code" , "math" , blockMath ( delim ) , {
190
+
191
+ if ( enableMathEnvs ) {
192
+ md . block . ruler . after ( "code" , "math" ,
193
+ blockMath ( / \\ b e g i n \{ ( [ a - z ] + ) \} / , / \\ e n d \{ ( [ a - z ] + ) \} / ) , {
184
194
alt : [ "paragraph" , "reference" , "blockquote" , "list" ]
185
195
} ) ;
186
- } ) ;
187
196
}
197
+ // Helper function for checking input
198
+ const isEmptyStr = elem => elem . trim ( ) === '' ;
199
+
200
+ inlineDelimiters . split ( '|' ) . forEach ( d => {
201
+ let delims = d . split ( ',' ) ;
202
+ if ( delims . length !== 2 || delims . some ( isEmptyStr ) ) {
203
+ console . error ( 'Invalid input in discourse_math_inline_delimiters!' ) ;
204
+ return ;
205
+ }
206
+ let startDelim = delims [ 0 ] . trim ( ) ;
207
+ let endDelim = delims [ 1 ] . trim ( ) ;
208
+ md . inline . ruler . after ( "escape" , "math" , inlineMath ( startDelim , endDelim ) ) ;
209
+ } ) ;
210
+
211
+ blockDelimiters . split ( '|' ) . forEach ( d => {
212
+ let delims = d . split ( ',' ) ;
213
+ if ( delims . length !== 2 || delims . some ( isEmptyStr ) ) {
214
+ console . error ( 'Invalid input in discourse_math_block_delimiters!' ) ;
215
+ return ;
216
+ }
217
+ let startDelim = delims [ 0 ] . trim ( ) ;
218
+ let endDelim = delims [ 1 ] . trim ( ) ;
219
+ md . block . ruler . after ( "code" , "math" , blockMath ( startDelim , endDelim ) , {
220
+ alt : [ "paragraph" , "reference" , "blockquote" , "list" ]
221
+ } ) ;
222
+ } ) ;
188
223
} ) ;
189
224
}
0 commit comments