Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/2 Fixes/7992.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Can now include a LaTeX-style equation without surrounding the equation with '$' in a markdown cell.
18 changes: 9 additions & 9 deletions src/datascience-ui/interactive-common/cellOutput.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import '../../client/common/extensions';

// tslint:disable-next-line: no-var-requires no-require-imports
const ansiToHtml = require('ansi-to-html');

import { nbformat } from '@jupyterlab/coreutils';
import { JSONObject } from '@phosphor/coreutils';
import ansiRegex from 'ansi-regex';
// tslint:disable-next-line: no-require-imports
import cloneDeep = require('lodash/cloneDeep');
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';
import * as React from 'react';

import '../../client/common/extensions';
import { concatMultilineStringInput, concatMultilineStringOutput } from '../../client/datascience/common';
import { Identifiers } from '../../client/datascience/constants';
import { CellState } from '../../client/datascience/types';
Expand All @@ -22,9 +15,16 @@ import { noop } from '../../test/core';
import { Image, ImageName } from '../react-common/image';
import { ImageButton } from '../react-common/imageButton';
import { getLocString } from '../react-common/locReactSide';
import { fixLatexEquations } from './latexManipulation';
import { ICellViewModel } from './mainState';
import { displayOrder, richestMimetype, transforms } from './transforms';

// tslint:disable-next-line: no-var-requires no-require-imports
const ansiToHtml = require('ansi-to-html');

// tslint:disable-next-line: no-require-imports
import cloneDeep = require('lodash/cloneDeep');

interface ICellOutputProps {
cellVM: ICellViewModel;
baseTheme: string;
Expand Down Expand Up @@ -172,7 +172,7 @@ export class CellOutput extends React.Component<ICellOutputProps> {
private renderMarkdownOutputs = () => {
const markdown = this.getMarkdownCell();
// React-markdown expects that the source is a string
const source = concatMultilineStringInput(markdown.source);
const source = fixLatexEquations(concatMultilineStringInput(markdown.source));
const Transform = transforms['text/markdown'];
const MarkdownClassName = 'markdown-cell-output';

Expand Down
38 changes: 38 additions & 0 deletions src/datascience-ui/interactive-common/latexManipulation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Adds '$$' to latex formulas that don't have a '$', allowing users to input the formula directly.
export function fixLatexEquations(input: string): string {
const block = '\n$$\n';

const beginIndexes = getAllIndexesOfRegex(input, /\\begin\{[a-z]*\*?\}/g);
const endIndexes = getAllIndexesOfRegex(input, /\\end\{[a-z]*\*?\}/g);

if (beginIndexes.length === endIndexes.length) {
for (let i = 0; i < beginIndexes.length; i += 1) {
const endOfEnd = input.indexOf('}', endIndexes[i] + 1 + 8 * i);

// Edge case, if the input starts with the latex formula we add the block at the beggining.
if (beginIndexes[i] === 0 && input[beginIndexes[i]] === '\\') {
input = block + input.slice(0, endOfEnd + 1) + block + input.slice(endOfEnd + 1, input.length);
// Normal case, if the latex formula starts with a '$' we don't do anything.
// Otherwise, we insert the block at the beginning and ending of the latex formula.
} else if (input[beginIndexes[i] - 1] !== '$') {
input = input.slice(0, beginIndexes[i] + block.length * 2 * i) + block + input.slice(beginIndexes[i] + block.length * 2 * i, endOfEnd + 1) + block + input.slice(endOfEnd + 1, input.length);
}
}
}

return input;
}

function getAllIndexesOfRegex(arr: string, value: RegExp): number[] {
const indexes = [];
let result;

// tslint:disable-next-line: no-conditional-assignment
while ((result = value.exec(arr)) !== null) {
indexes.push(result.index);
}

return indexes;
}
102 changes: 102 additions & 0 deletions src/test/datascience/latexManipulation.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { expect } from 'chai';
import { fixLatexEquations } from '../../datascience-ui/interactive-common/latexManipulation';

// tslint:disable: max-func-body-length
suite('Data Science - LaTeX Manipulation', () => {
const markdown1 = `\\begin{align}
\\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\
\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\
\\nabla \\cdot \\vec{\\mathbf{B}} & = 0
\\end{align}
sample text`;

const output1 = `
$$
\\begin{align}
\\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\
\\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\
\\nabla \\cdot \\vec{\\mathbf{B}} & = 0
\\end{align}
$$

sample text`;

const markdown2 = `$\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}$
sample text
$\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}$
sample text`;

const markdown3 = `\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
sample text
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
sample text
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
sample text

sample text
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}`;

const output3 = `
$$
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
$$

sample text

$$
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
$$

sample text

$$
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
$$

sample text

sample text

$$
\\begin{align*}
(a+b)^2 = a^2+2ab+b^2
\\end{align*}
$$
`;

test('Latex - Equations don\'t have $$', () => {
const result = fixLatexEquations(markdown1);
expect(result).to.be.equal(output1, 'Result is incorrect');
});

test('Latex - Equations have $', () => {
const result = fixLatexEquations(markdown2);
expect(result).to.be.equal(markdown2, 'Result is incorrect');
});

test('Latex - Multiple equations don\'t have $$', () => {
const result = fixLatexEquations(markdown3);
expect(result).to.be.equal(output3, 'Result is incorrect');
});
});