Skip to content

Commit e322aee

Browse files
committed
Revamp options
1 parent e808416 commit e322aee

File tree

3 files changed

+75
-38
lines changed

3 files changed

+75
-38
lines changed

assets/javascripts/lib/discourse-markdown/discourse-math.js.es6

+67-32
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ function isSafeBoundary(character_code, delimiter_code, md) {
2323
return false;
2424
}
2525

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);
2831
let pos = state.pos,
2932
posMax = state.posMax;
3033

@@ -37,7 +40,7 @@ let inlineMath = delimiter => (state, silent) => {
3740
}
3841

3942
// too short
40-
if (state.src.charCodeAt(pos + 1) === delimiter_code) {
43+
if (state.src.charCodeAt(pos + 1) === end_delimiter_code) {
4144
return false;
4245
}
4346

@@ -51,7 +54,7 @@ let inlineMath = delimiter => (state, silent) => {
5154
let found;
5255
for (let i = pos + 1; i < posMax; i++) {
5356
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 /* \ */) {
5558
found = i;
5659
break;
5760
}
@@ -63,7 +66,7 @@ let inlineMath = delimiter => (state, silent) => {
6366

6467
if (found + 1 <= posMax) {
6568
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)) {
6770
return false;
6871
}
6972
}
@@ -72,7 +75,7 @@ let inlineMath = delimiter => (state, silent) => {
7275
let token = state.push("html_raw", "", 0);
7376

7477
const escaped = state.md.utils.escapeHtml(data);
75-
let math_class = delimiter_code === 37 /* % */ ? "'asciimath'" : "'math'";
78+
let math_class = startDelimiter === endDelimiter === '%' ? "'asciimath'" : "'math'";
7679
token.content = `<span class=${math_class}>${escaped}</span>`;
7780
state.pos = found + 1;
7881
return true;
@@ -83,8 +86,8 @@ function isBlockMarker(state, start, max, md, blockMarker) {
8386
if (!state.src.startsWith(blockMarker, start)) {
8487
return false;
8588
}
86-
87-
// ensure we only have spaces and newline after blockmarker
89+
90+
// ensure we only have spaces and newlines after block math marker
8891
for (let i = start + blockMarker.length; i < max; i++) {
8992
if (!md.utils.isSpace(state.src.charCodeAt(i))) {
9093
return false;
@@ -94,11 +97,26 @@ function isBlockMarker(state, start, max, md, blockMarker) {
9497
return true;
9598
}
9699

97-
let blockMath = blockMarker => (state, startLine, endLine, silent) => {
100+
let blockMath = (startBlockMathMarker, endBlockMathMarker) => (state, startLine, endLine, silent) => {
98101
let start = state.bMarks[startLine] + state.tShift[startLine],
99102
max = state.eMarks[startLine];
100103

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)) {
102120
return false;
103121
}
104122

@@ -122,7 +140,7 @@ let blockMath = blockMarker => (state, startLine, endLine, silent) => {
122140
state.bMarks[nextLine] + state.tShift[nextLine],
123141
state.eMarks[nextLine],
124142
state.md,
125-
blockMarker.replace('\\begin{', '\\end{')
143+
endBlockMarker
126144
)
127145
) {
128146
closed = true;
@@ -132,12 +150,12 @@ let blockMath = blockMarker => (state, startLine, endLine, silent) => {
132150

133151
let token = state.push("html_raw", "", 0);
134152

135-
// Blockmarker starting with \begin{ end ending with '\end{'
153+
// Math environment blockmarkers '\begin{}' and '\end{}'
136154
// needs to be passed to the TeX engine
137-
let endContent = blockMarker.startsWith('\\begin{') || !closed ?
155+
let endContent = endBlockMarker.startsWith('\\end{') || !closed ?
138156
state.eMarks[nextLine] : state.eMarks[nextLine - 1];
139157

140-
let startContent = blockMarker.startsWith('\\begin{') ?
158+
let startContent = startBlockMarker.startsWith('\\begin{') ?
141159
state.bMarks[startLine] : state.bMarks[startLine + 1] + state.tShift[startLine + 1];
142160

143161
let content = state.src.slice(startContent, endContent);
@@ -155,35 +173,52 @@ export function setup(helper) {
155173
return;
156174
}
157175

158-
let enable_asciimath;
176+
let enableAsciiMath, enableMathEnvs;
159177
let inlineDelimiters, blockDelimiters;
160178
helper.registerOptions((opts, siteSettings) => {
161179
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;
163182
inlineDelimiters = siteSettings.discourse_math_inline_delimiters;
164183
blockDelimiters = siteSettings.discourse_math_block_delimiters;
165184
});
166185

167186
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('%', '%'));
179189
}
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(/\\begin\{([a-z]+)\}/, /\\end\{([a-z]+)\}/), {
184194
alt: ["paragraph", "reference", "blockquote", "list"]
185195
});
186-
});
187196
}
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+
});
188223
});
189224
}

config/locales/server.en.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ en:
88
discourse_math_zoom_on_hover: 'Zoom 200% on hover (MathJax only)'
99
discourse_math_enable_accessibility: 'Enable accessibility features (MathJax only)'
1010
discourse_math_enable_asciimath: 'Enable asciimath (will add special processing to % delimited input) (MathJax only)'
11-
discourse_math_inline_delimiters: 'You can have multiple delimiters for inline math, but each must be single character'
12-
discourse_math_block_delimiters: 'You can have multiple delimiters for block math. Delimiters starting with "\begin{" will be passed to the LaTeX engine and are expected to end with the corresponding \end{} command'
11+
discourse_math_inline_delimiters: 'You can have multiple delimiters for inline math'
12+
discourse_math_block_delimiters: 'You can have multiple delimiters for block math. Delimiters starting with "\begin{}" will be passed to the LaTeX engine and should to end with the corresponding \end{} command'
13+
discourse_math_process_tex_environments: 'Enable processing of "\begin{*}...\end{*}" environments (MathJax only)'

config/settings.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ plugins:
1010
- mathjax
1111
- katex
1212
discourse_math_inline_delimiters:
13-
default: '$'
13+
default: '$,$'
1414
client: true
1515
type: list
16-
list_type: compact
1716
discourse_math_block_delimiters:
18-
default: '$$|\\begin{align}'
17+
default: '$$,$$'
1918
client: true
2019
type: list
21-
list_type: compact
20+
discourse_math_process_tex_environments:
21+
default: false
22+
client: true
2223
discourse_math_zoom_on_hover:
2324
default: false
2425
client: true

0 commit comments

Comments
 (0)