Skip to content

Commit ff477c9

Browse files
committed
Add option to allow whitespace padded inline expressions
resolves #21
1 parent 441c8b6 commit ff477c9

File tree

4 files changed

+79
-49
lines changed

4 files changed

+79
-49
lines changed

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ import markdownItMath from "markdown-it-math";
6868

6969
// Optional (with defaults)
7070
const options = {
71-
inlineDelimiters: ["$", ["$`", "`$"]]
71+
inlineDelimiters: ["$", ["$`", "`$"]],
72+
inlineAllowWhiteSpacePadding: false,
7273
blockDelimiters: "$$",
7374
defaultRendererOptions,
7475
inlineCustomElement, // see below
@@ -146,6 +147,11 @@ default renderer.
146147
strings or pairs containing empty strings are ignored. If no valid
147148
strings or pairs are provided, it will turn off the rule.
148149
Default ``["$", ["$`", "`$"]]``.
150+
- `inlineAllowWhiteSpacePadding`: Whether to allow whitespace
151+
immediately after the opening delimiter and immediately before the
152+
closing delimiter. You may want this if you use e.g. ``$`...`$`` or
153+
`\(...\)` as delimiters where the risk of non-intended math
154+
expression is low.
149155
- `blockDelimiters`: Same as above, but for block expressions. Default `"$$"`.
150156
- `defaultRendererOptions`: The options passed into the default
151157
renderer. Ignored if you use a custom renderer. Default `{}`
@@ -299,7 +305,7 @@ const md = markdownIt().use(markdownItMath, {
299305
return temml.renderToString(src);
300306
},
301307

302-
blockDelimiters: [$$, ["\\[", "\\]"]],
308+
blockDelimiters: ["$$", ["\\[", "\\]"]],
303309
blockRenderer(src, token) {
304310
if (token.markup === "$$") {
305311
return mathup(src, { display: "block" }).toString();

index.js

+25-8
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ function fromDelimiterOption(delimiters) {
5757
}
5858

5959
/**
60-
* @param {Array<[string, string]>} delimiters
60+
* @param {object} options
61+
* @param {Array<[string, string]>} options.delimiters
62+
* @param {boolean} options.allowWhiteSpacePadding
6163
* @returns {RuleInline}
6264
*/
63-
function createInlineMathRule(delimiters) {
65+
function createInlineMathRule({ delimiters, allowWhiteSpacePadding }) {
6466
return (state, silent) => {
6567
const start = state.pos;
6668

@@ -76,8 +78,11 @@ function createInlineMathRule(delimiters) {
7678
for (const [open, close] of markers) {
7779
const pos = start + open.length;
7880

79-
if (state.md.utils.isWhiteSpace(state.src.charCodeAt(pos))) {
80-
// Don’t allow whitespace immediately after open delimiter ... for now.
81+
if (
82+
state.md.utils.isWhiteSpace(state.src.charCodeAt(pos)) &&
83+
!allowWhiteSpacePadding
84+
) {
85+
// Don’t allow whitespace immediately after open delimiter
8186
continue;
8287
}
8388

@@ -88,12 +93,19 @@ function createInlineMathRule(delimiters) {
8893
continue;
8994
}
9095

91-
// Don’t allow whitespace immediately before close delimiter ... for now.
92-
if (state.md.utils.isWhiteSpace(state.src.charCodeAt(matchStart - 1))) {
96+
if (
97+
state.md.utils.isWhiteSpace(state.src.charCodeAt(matchStart - 1)) &&
98+
!allowWhiteSpacePadding
99+
) {
100+
// Don’t allow whitespace immediately before close delimiter
93101
continue;
94102
}
95103

96-
const content = state.src.slice(pos, matchStart).replaceAll("\n", " ");
104+
let content = state.src.slice(pos, matchStart).replaceAll("\n", " ");
105+
106+
if (allowWhiteSpacePadding) {
107+
content = content.replace(/^ (.+) $/, "$1");
108+
}
97109

98110
if (!silent) {
99111
const token = state.push("math_inline", "math", 0);
@@ -281,6 +293,7 @@ function defaultBlockRenderer(options, md) {
281293
* @property {string} [inlineClose] - Deprecated: Use inlineDelimiters
282294
* @property {CustomElementOption} [inlineCustomElement] - If you want to render to a custom element.
283295
* @property {Renderer} [inlineRenderer] - Custom renderer for inline math. Default mathup.
296+
* @property {boolean} [inlineAllowWhiteSpacePadding] - If you want allow inline math to start or end with whitespace.
284297
* @property {string | Delimiter[]} [blockDelimiters] - Block math delimters.
285298
* @property {string} [blockOpen] - Deprecated: Use blockDelimiters
286299
* @property {string} [blockClose] - Deprecated: Use blockDelimiters
@@ -295,6 +308,7 @@ export default function markdownItMath(
295308
{
296309
defaultRendererOptions = {},
297310

311+
inlineAllowWhiteSpacePadding = false,
298312
inlineOpen,
299313
inlineClose,
300314
inlineDelimiters = inlineOpen && inlineClose
@@ -320,7 +334,10 @@ export default function markdownItMath(
320334
) {
321335
const inlineDelimitersArray = fromDelimiterOption(inlineDelimiters);
322336
if (inlineDelimitersArray) {
323-
const inlineMathRule = createInlineMathRule(inlineDelimitersArray);
337+
const inlineMathRule = createInlineMathRule({
338+
delimiters: inlineDelimitersArray,
339+
allowWhiteSpacePadding: inlineAllowWhiteSpacePadding,
340+
});
324341

325342
md.inline.ruler.before("escape", "math_inline", inlineMathRule);
326343

test/test.js

+46-15
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,10 @@ $$
371371
});
372372

373373
suite("Options", () => {
374-
test("Thick dollar delims", (t) => {
374+
test("Thick dollar delims", () => {
375375
const md = markdownIt().use(markdownItMath, {
376+
inlineCustomElement,
377+
blockCustomElement,
376378
inlineDelimiters: "$$",
377379
blockDelimiters: "$$$",
378380
});
@@ -384,10 +386,13 @@ $$$
384386
$$$
385387
`;
386388

387-
t.assert.snapshot(md.render(src));
389+
assert.equal(
390+
md.render(src),
391+
[p(`Foo ${mathspan("1+1 = 2")} bar`), mathblock("1+1 = 2")].join(""),
392+
);
388393
});
389394

390-
test("No delimiters turns off rules", (t) => {
395+
test("No delimiters turns off rules", () => {
391396
const md = markdownIt().use(markdownItMath, {
392397
inlineDelimiters: "",
393398
blockDelimiters: [],
@@ -400,13 +405,15 @@ $$
400405
$$
401406
`;
402407

403-
t.assert.snapshot(md.render(src));
408+
assert.equal(md.render(src), p("Foo $1+1 = 2$ bar", "$$\n1+1 = 2\n$$"));
404409
});
405410

406-
test("Empty open or close dilimeters are filtered out", (t) => {
411+
test("Empty open or close dilimeters are filtered out", () => {
407412
const md = markdownIt().use(markdownItMath, {
408-
inlineDelimiters: ["", ["", "$"]],
413+
blockCustomElement,
409414
blockDelimiters: [["$$", ""]],
415+
inlineCustomElement,
416+
inlineDelimiters: ["", ["", "$"]],
410417
});
411418

412419
const src = `Foo $1+1 = 2$ bar
@@ -416,21 +423,37 @@ $$
416423
$$
417424
`;
418425

419-
t.assert.snapshot(md.render(src));
426+
assert.equal(md.render(src), p("Foo $1+1 = 2$ bar", "$$\n1+1 = 2\n$$"));
420427
});
421428

422-
test("Space dollar delims", (t) => {
429+
test("Space dollar delims", () => {
423430
const md = markdownIt().use(markdownItMath, {
431+
blockCustomElement,
432+
inlineCustomElement,
424433
inlineDelimiters: [["$ ", " $"]],
425434
});
426435

427-
const src = `Foo $ 1+1 = 2 $ bar`;
436+
const src = `foo $ 1+1 = 2 $ bar`;
428437

429-
t.assert.snapshot(md.render(src));
438+
assert.equal(md.render(src), p(`foo ${mathspan("1+1 = 2")} bar`));
439+
});
440+
441+
test("Allow inline space padding", () => {
442+
const md = markdownIt().use(markdownItMath, {
443+
blockCustomElement,
444+
inlineCustomElement,
445+
inlineAllowWhiteSpacePadding: true,
446+
});
447+
448+
const src = "foo $` 1+1 = 2 `$ bar";
449+
450+
assert.equal(md.render(src), p(`foo ${mathspan("1+1 = 2")} bar`));
430451
});
431452

432-
test("LaTeX style delims", (t) => {
453+
test("LaTeX style delims", () => {
433454
const md = markdownIt().use(markdownItMath, {
455+
inlineCustomElement,
456+
blockCustomElement,
434457
inlineDelimiters: [["\\(", "\\)"]],
435458
blockDelimiters: [["\\[", "\\]"]],
436459
});
@@ -442,7 +465,10 @@ $$
442465
\]
443466
`;
444467

445-
t.assert.snapshot(md.render(src));
468+
assert.equal(
469+
md.render(src),
470+
[p(`Foo ${mathspan("1+1 = 2")} bar`), mathblock("1+1 = 2")].join(""),
471+
);
446472
});
447473

448474
test("Different options for the default renderer", (t) => {
@@ -538,17 +564,22 @@ $$`;
538564
});
539565

540566
suite("Depricated", () => {
541-
test("inlineOpen inlineClose blockOpen blockClose", (t) => {
542-
const md = markdownIt().use(markdownItMath, {
567+
test("inlineOpen inlineClose blockOpen blockClose", () => {
568+
const mdDepricated = markdownIt().use(markdownItMath, {
543569
inlineOpen: "$((",
544570
inlineClose: "))$",
545571
blockOpen: "$[[",
546572
blockClose: "]]$",
547573
});
548574

575+
const mdRecommended = markdownIt().use(markdownItMath, {
576+
inlineDelimiters: [["$((", "))$"]],
577+
blockDelimiters: [["$[[", "]]$"]],
578+
});
579+
549580
const src = '$(("inline"))$\n$[["block"]]$';
550581

551-
t.assert.snapshot(md.render(src));
582+
assert.equal(mdDepricated.render(src), mdRecommended.render(src));
552583
});
553584
});
554585
});

test/test.js.snapshot

-24
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,7 @@
1-
exports[`Options > Depricated > inlineOpen inlineClose blockOpen blockClose 1`] = `
2-
"<p><math><mtext>inline</mtext></math></p>\\n<math display=\\"block\\"><mtext>block</mtext></math>\\n"
3-
`;
4-
51
exports[`Options > Different options for the default renderer 1`] = `
62
"<p><math><mn>40,2</mn></math></p>\\n<math display=\\"block\\"><mn>40,2</mn></math>\\n"
73
`;
84

9-
exports[`Options > Empty open or close dilimeters are filtered out 1`] = `
10-
"<p>Foo $1+1 = 2$ bar</p>\\n<p>$$\\n1+1 = 2\\n$$</p>\\n"
11-
`;
12-
13-
exports[`Options > LaTeX style delims 1`] = `
14-
"<p>Foo <math><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math> bar</p>\\n<math display=\\"block\\"><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math>\\n"
15-
`;
16-
17-
exports[`Options > No delimiters turns off rules 1`] = `
18-
"<p>Foo $1+1 = 2$ bar</p>\\n<p>$$\\n1+1 = 2\\n$$</p>\\n"
19-
`;
20-
21-
exports[`Options > Space dollar delims 1`] = `
22-
"<p>Foo <math><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math> bar</p>\\n"
23-
`;
24-
25-
exports[`Options > Thick dollar delims 1`] = `
26-
"<p>Foo <math><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math> bar</p>\\n<math display=\\"block\\"><mrow><mn>1</mn><mo>+</mo><mn>1</mn></mrow><mo>=</mo><mn>2</mn></math>\\n"
27-
`;
28-
295
exports[`Options > Use Temml as renderer > block 1`] = `
306
"<math display=\\"block\\" class=\\"tml-display\\" style=\\"display:block math;\\"><mrow><mrow><mi>sin</mi><mo>⁡</mo></mrow><mo form=\\"prefix\\" stretchy=\\"false\\">(</mo><mn>2</mn><mi>π</mi><mo form=\\"postfix\\" stretchy=\\"false\\">)</mo></mrow></math>\\n"
317
`;

0 commit comments

Comments
 (0)