diff --git a/src/languages/definitions/latex/latex.test.ts b/src/languages/definitions/latex/latex.test.ts new file mode 100644 index 0000000000..3c507ec3da --- /dev/null +++ b/src/languages/definitions/latex/latex.test.ts @@ -0,0 +1,229 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('latex', [ + // Comment + [ + { + line: '% This is a comment', + tokens: [{ startIndex: 0, type: 'comment.latex' }] + } + ], + + // Known (builtin) command + [ + { + line: '\\textbf', + tokens: [ + { startIndex: 0, type: 'keyword.control.latex' }, + { startIndex: 1, type: 'keyword.predefined.latex' } + ] + } + ], + + // Unknown (non-builtin) command + [ + { + line: '\\myCustomCommand', + tokens: [ + { startIndex: 0, type: 'keyword.control.latex' }, + { startIndex: 1, type: 'keyword.latex' } + ] + } + ], + + // \begin{document} + [ + { + line: '\\begin{document}', + tokens: [ + { startIndex: 0, type: 'keyword.predefined.latex' }, + { startIndex: 6, type: 'delimiter.curly.latex' }, + { startIndex: 7, type: 'tag.latex' }, + { startIndex: 15, type: 'delimiter.curly.latex' } + ] + } + ], + + // \end{document} + [ + { + line: '\\end{document}', + tokens: [ + { startIndex: 0, type: 'keyword.predefined.latex' }, + { startIndex: 4, type: 'delimiter.curly.latex' }, + { startIndex: 5, type: 'tag.latex' }, + { startIndex: 13, type: 'delimiter.curly.latex' } + ] + } + ], + + // Inline math $x$ + [ + { + line: '$x$', + tokens: [ + { startIndex: 0, type: 'string.math.inline.latex' }, + { startIndex: 1, type: 'string.math.latex' }, + { startIndex: 2, type: 'string.math.inline.latex' } + ] + } + ], + + // Display math $$x$$ + [ + { + line: '$$x$$', + tokens: [ + { startIndex: 0, type: 'string.math.display.latex' }, + { startIndex: 2, type: 'string.math.latex' }, + { startIndex: 3, type: 'string.math.display.latex' } + ] + } + ], + + // Numeric argument #1 + [ + { + line: '#1', + tokens: [{ startIndex: 0, type: 'number.arg.latex' }] + } + ], + + // Dimension with unit + [ + { + line: '1.5em', + tokens: [{ startIndex: 0, type: 'number.len.latex' }] + } + ], + + // Single-char command \\ + [ + { + line: '\\\\', + tokens: [{ startIndex: 0, type: 'keyword.latex' }] + } + ], + + // Special chars + [ + { + line: 'a & b', + tokens: [ + { startIndex: 0, type: '' }, + { startIndex: 2, type: 'keyword.latex' }, + { startIndex: 3, type: '' } + ] + } + ], + + // Internal command with @ + [ + { + line: '\\@fooBar', + tokens: [{ startIndex: 0, type: 'keyword.at.latex' }] + } + ], + + // Additional begin/end environment names + [ + { + line: '\\begin{align*}', + tokens: [ + { startIndex: 0, type: 'keyword.predefined.latex' }, + { startIndex: 6, type: 'delimiter.curly.latex' }, + { startIndex: 7, type: 'tag.latex' }, + { startIndex: 13, type: 'delimiter.curly.latex' } + ] + } + ], + [ + { + line: '\\end{my-env}', + tokens: [ + { startIndex: 0, type: 'keyword.predefined.latex' }, + { startIndex: 4, type: 'delimiter.curly.latex' }, + { startIndex: 5, type: 'tag.latex' }, + { startIndex: 11, type: 'delimiter.curly.latex' } + ] + } + ], + + // Inline math with operator and number + [ + { + line: '$x+1$', + tokens: [ + { startIndex: 0, type: 'string.math.inline.latex' }, + { startIndex: 1, type: 'string.math.latex' }, + { startIndex: 2, type: 'operator.latex' }, + { startIndex: 3, type: 'number.latex' }, + { startIndex: 4, type: 'string.math.inline.latex' } + ] + } + ], + + // Display math with command and braces + [ + { + line: '$$\\frac{1}{2}$$', + tokens: [ + { startIndex: 0, type: 'string.math.display.latex' }, + { startIndex: 2, type: 'keyword.math.latex' }, + { startIndex: 7, type: 'delimiter.curly.latex' }, + { startIndex: 8, type: 'number.latex' }, + { startIndex: 9, type: 'delimiter.curly.latex' }, + { startIndex: 11, type: 'number.latex' }, + { startIndex: 12, type: 'delimiter.curly.latex' }, + { startIndex: 13, type: 'string.math.display.latex' } + ] + } + ], + + // Escaped special command + [ + { + line: '\\$', + tokens: [{ startIndex: 0, type: 'keyword.latex' }] + } + ], + + // Additional numeric arg and dimensions + [ + { + line: '#9', + tokens: [{ startIndex: 0, type: 'number.arg.latex' }] + } + ], + [ + { + line: '-2.0 cm', + tokens: [{ startIndex: 0, type: 'number.len.latex' }] + } + ], + + // Builtin vs unknown command boundary + [ + { + line: '\\Huge', + tokens: [ + { startIndex: 0, type: 'keyword.control.latex' }, + { startIndex: 1, type: 'keyword.predefined.latex' } + ] + } + ], + [ + { + line: '\\textbffoo', + tokens: [ + { startIndex: 0, type: 'keyword.control.latex' }, + { startIndex: 1, type: 'keyword.latex' } + ] + } + ] +]); diff --git a/src/languages/definitions/latex/latex.ts b/src/languages/definitions/latex/latex.ts new file mode 100644 index 0000000000..4fb94e3e22 --- /dev/null +++ b/src/languages/definitions/latex/latex.ts @@ -0,0 +1,358 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { languages } from '../../../editor'; + +export const conf: languages.LanguageConfiguration = { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '$', close: '$' } + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '$', close: '$' } + ], + comments: { + lineComment: '%' + } +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.latex', + + // Built-in LaTeX commands (from madoko latex.json) + builtins: [ + 'addcontentsline', + 'addtocontents', + 'addtocounter', + 'address', + 'addtolength', + 'addvspace', + 'alph', + 'appendix', + 'arabic', + 'author', + 'backslash', + 'baselineskip', + 'baselinestretch', + 'bf', + 'bibitem', + 'bigskipamount', + 'bigskip', + 'boldmath', + 'boldsymbol', + 'cal', + 'caption', + 'cdots', + 'centering', + 'chapter', + 'circle', + 'cite', + 'cleardoublepage', + 'clearpage', + 'cline', + 'closing', + 'color', + 'copyright', + 'dashbox', + 'date', + 'ddots', + 'documentclass', + 'dotfill', + 'em', + 'emph', + 'ensuremath', + 'epigraph', + 'euro', + 'fbox', + 'flushbottom', + 'fnsymbol', + 'footnote', + 'footnotemark', + 'footnotesize', + 'footnotetext', + 'frac', + 'frame', + 'framebox', + 'frenchspacing', + 'hfill', + 'hline', + 'href', + 'hrulefill', + 'hspace', + 'huge', + 'Huge', + 'hyphenation', + 'include', + 'includegraphics', + 'includeonly', + 'indent', + 'input', + 'it', + 'item', + 'kill', + 'label', + 'large', + 'Large', + 'LARGE', + 'LaTeX', + 'LaTeXe', + 'ldots', + 'left', + 'lefteqn', + 'line', + 'linebreak', + 'linethickness', + 'linewidth', + 'listoffigures', + 'listoftables', + 'location', + 'makebox', + 'maketitle', + 'markboth', + 'mathcal', + 'mathop', + 'mbox', + 'medskip', + 'multicolumn', + 'multiput', + 'newcommand', + 'newcolumntype', + 'newcounter', + 'newenvironment', + 'newfont', + 'newlength', + 'newline', + 'newpage', + 'newsavebox', + 'newtheorem', + 'nocite', + 'noindent', + 'nolinebreak', + 'nonfrenchspacing', + 'normalsize', + 'nopagebreak', + 'not', + 'onecolumn', + 'opening', + 'oval', + 'overbrace', + 'overline', + 'pagebreak', + 'pagenumbering', + 'pageref', + 'pagestyle', + 'par', + 'paragraph', + 'parbox', + 'parindent', + 'parskip', + 'part', + 'protect', + 'providecommand', + 'put', + 'raggedbottom', + 'raggedleft', + 'raggedright', + 'raisebox', + 'ref', + 'renewcommand', + 'right', + 'rm', + 'roman', + 'rule', + 'savebox', + 'sbox', + 'sc', + 'scriptsize', + 'section', + 'setcounter', + 'setlength', + 'settowidth', + 'sf', + 'shortstack', + 'signature', + 'sl', + 'slash', + 'small', + 'smallskip', + 'sout', + 'space', + 'sqrt', + 'stackrel', + 'stepcounter', + 'subparagraph', + 'subsection', + 'subsubsection', + 'tableofcontents', + 'telephone', + 'TeX', + 'textbf', + 'textcolor', + 'textit', + 'textmd', + 'textnormal', + 'textrm', + 'textsc', + 'textsf', + 'textsl', + 'texttt', + 'textup', + 'textwidth', + 'textheight', + 'thanks', + 'thispagestyle', + 'tiny', + 'title', + 'today', + 'tt', + 'twocolumn', + 'typeout', + 'typein', + 'uline', + 'underbrace', + 'underline', + 'unitlength', + 'usebox', + 'usecounter', + 'uwave', + 'value', + 'vbox', + 'vcenter', + 'vdots', + 'vector', + 'verb', + 'vfill', + 'vline', + 'vphantom', + 'vspace', + 'RequirePackage', + 'NeedsTeXFormat', + 'usepackage', + 'documentstyle', + 'def', + 'edef', + 'defcommand', + 'if', + 'ifdim', + 'ifnum', + 'ifx', + 'fi', + 'else', + 'begingroup', + 'endgroup', + 'definecolor', + 'textcolor', + 'eifstrequal', 'eeifstrequal' + ], + + tokenizer: { + root: [ + // Whitespace and comments + { include: '@whitespace' }, + + // Display math $$...$$ — must come before inline math $ + [/\$\$/, { token: 'string.math.display', next: '@displayMath' }], + + // Inline math $...$ + [/\$/, { token: 'string.math.inline', next: '@inlineMath' }], + + // \begin{envname} + [/\\begin(?=\s*\{)/, { token: 'keyword.predefined', next: '@envNameBegin' }], + + // \end{envname} + [/\\end(?=\s*\{)/, { token: 'keyword.predefined', next: '@envNameEnd' }], + + // \@letters (package/class internal commands) + [/\\@[a-zA-Z@]+/, 'keyword.at'], + + // Named commands: split backslash and name into separate tokens + // so we can check the name against the builtins list + [ + /(\\)([a-zA-Z]+)/, + [ + 'keyword.control', + { + cases: { + '@builtins': 'keyword.predefined', + '@default': 'keyword' + } + } + ] + ], + + // Single-character commands: \ followed by non-letter (e.g. \\ \$ \% \& \{ \}) + [/\\[^a-zA-Z@]/, 'keyword'], + + // Numeric arguments #1, #2, ... + [/#[0-9]/, 'number.arg'], + + // Dimensions with LaTeX units + [/[+-]?\d+(\.\d+)?\s*(em|ex|pt|pc|sp|cm|mm|in)\b/, 'number.len'], + + // Brackets + [/[{}()\[\]]/, '@brackets'], + + // Special LaTeX characters + [/[&~_^]/, 'keyword'], + ], + + whitespace: [ + [/[ \t\r\n]+/, ''], + [/%.*$/, 'comment'], + ], + + // After \begin — captures {envname} + envNameBegin: [ + [/\s+/, ''], + [/\{/, 'delimiter.curly'], + [/[\w@*\-]+/, 'tag'], + [/\}/, { token: 'delimiter.curly', next: '@pop' }], + ['', '', '@pop'], + ], + + // After \end — captures {envname} + envNameEnd: [ + [/\s+/, ''], + [/\{/, 'delimiter.curly'], + [/[\w@*\-]+/, 'tag'], + [/\}/, { token: 'delimiter.curly', next: '@pop' }], + ['', '', '@pop'], + ], + + // Inside $...$ + inlineMath: [ + [/\$/, { token: 'string.math.inline', next: '@pop' }], + { include: '@mathContent' }, + ], + + // Inside $$...$$ + displayMath: [ + [/\$\$/, { token: 'string.math.display', next: '@pop' }], + { include: '@mathContent' }, + ], + + // Shared math content + mathContent: [ + { include: '@whitespace' }, + [/\\[a-zA-Z]+/, 'keyword.math'], + [/\\[^a-zA-Z]/, 'keyword.math'], + [/[{}()\[\]]/, '@brackets'], + [/[+\-*/=<>!,;|]/, 'operator'], + [/\d+(\.\d+)?/, 'number'], + [/[^\\$\s+\-*/=<>!,;|{}()\[\]]+/, 'string.math'], + ], + } +}; diff --git a/src/languages/definitions/latex/register.ts b/src/languages/definitions/latex/register.ts new file mode 100644 index 0000000000..62f48288a8 --- /dev/null +++ b/src/languages/definitions/latex/register.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerLanguage } from '../_.contribution'; + +registerLanguage({ + id: 'latex', + extensions: ['.tex', '.latex', '.sty', '.cls'], + aliases: ['LaTeX', 'latex'], + mimetypes: ['application/x-latex'], + loader: () => import('./latex') +}); diff --git a/src/languages/definitions/mathjax/mathjax.test.ts b/src/languages/definitions/mathjax/mathjax.test.ts new file mode 100644 index 0000000000..2ca7242fdb --- /dev/null +++ b/src/languages/definitions/mathjax/mathjax.test.ts @@ -0,0 +1,804 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('mathjax', [ + + // --- Comments --- + [ + { + line: '% a comment', + tokens: [{ startIndex: 0, type: 'comment.mathjax' }] + } + ], + [ + { + line: 'x % inline comment', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'comment.mathjax' } + ] + } + ], + + // --- Numbers --- + [ + { + line: '42', + tokens: [{ startIndex: 0, type: 'number.mathjax' }] + } + ], + [ + { + line: '3.14', + tokens: [{ startIndex: 0, type: 'number.mathjax' }] + } + ], + [ + { + line: '0.5', + tokens: [{ startIndex: 0, type: 'number.mathjax' }] + } + ], + + // --- Variables (single letters) --- + [ + { + line: 'x', + tokens: [{ startIndex: 0, type: 'variable.mathjax' }] + } + ], + [ + { + line: 'n', + tokens: [{ startIndex: 0, type: 'variable.mathjax' }] + } + ], + + // --- Operators --- + [ + { + line: 'a + b', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'operator.mathjax' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'variable.mathjax' } + ] + } + ], + [ + { + line: 'f = g', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'operator.mathjax' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'variable.mathjax' } + ] + } + ], + + // --- Superscript and subscript --- + [ + { + line: 'x^2', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' }, + { startIndex: 2, type: 'number.mathjax' } + ] + } + ], + [ + { + line: 'a_n', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' }, + { startIndex: 2, type: 'variable.mathjax' } + ] + } + ], + [ + { + line: 'x_{n+1}', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' }, + { startIndex: 2, type: 'delimiter.curly.mathjax' }, + { startIndex: 3, type: 'variable.mathjax' }, + { startIndex: 4, type: 'operator.mathjax' }, + { startIndex: 5, type: 'number.mathjax' }, + { startIndex: 6, type: 'delimiter.curly.mathjax' } + ] + } + ], + [ + { + line: '\\beta_2', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.greek.mathjax' }, + { startIndex: 5, type: 'keyword.operator.mathjax' }, + { startIndex: 6, type: 'number.mathjax' } + ] + } + ], + + // --- Alignment operator --- + [ + { + line: 'a & b', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'keyword.operator.mathjax' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'variable.mathjax' } + ] + } + ], + + // --- Brackets --- + [ + { + line: '(a + b)', + tokens: [ + { startIndex: 0, type: 'delimiter.parenthesis.mathjax' }, + { startIndex: 1, type: 'variable.mathjax' }, + { startIndex: 2, type: '' }, + { startIndex: 3, type: 'operator.mathjax' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'variable.mathjax' }, + { startIndex: 6, type: 'delimiter.parenthesis.mathjax' } + ] + } + ], + [ + { + line: '{a}', + tokens: [ + { startIndex: 0, type: 'delimiter.curly.mathjax' }, + { startIndex: 1, type: 'variable.mathjax' }, + { startIndex: 2, type: 'delimiter.curly.mathjax' } + ] + } + ], + + // --- Double backslash (line break) --- + [ + { + line: '\\\\', + tokens: [{ startIndex: 0, type: 'keyword.mathjax' }] + } + ], + + // --- Single-char commands --- + [ + { + line: '\\,', + tokens: [{ startIndex: 0, type: 'keyword.mathjax' }] + } + ], + [ + { + line: '\\!', + tokens: [{ startIndex: 0, type: 'keyword.mathjax' }] + } + ], + [ + { + line: '\\{', + tokens: [{ startIndex: 0, type: 'keyword.mathjax' }] + } + ], + + // --- Greek letters --- + [ + { + line: '\\alpha', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.greek.mathjax' } + ] + } + ], + [ + { + line: '\\Omega', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.greek.mathjax' } + ] + } + ], + [ + { + line: '\\varepsilon', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.greek.mathjax' } + ] + } + ], + [ + { + // Hebrew letter + line: '\\aleph', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.greek.mathjax' } + ] + } + ], + + // --- Math functions --- + [ + { + line: '\\sin', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + [ + { + line: '\\arctan', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + [ + { + line: '\\lim', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + [ + { + line: '\\limsup', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + [ + { + line: '\\gcd', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + + // --- Math operators (structural/large) --- + [ + { + line: '\\frac', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + line: '\\sqrt', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + line: '\\int', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + line: '\\sum', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + line: '\\bigcup', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + line: '\\partial', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + + // --- Relations --- + [ + { + line: '\\leq', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.relation.mathjax' } + ] + } + ], + [ + { + line: '\\subseteq', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.relation.mathjax' } + ] + } + ], + [ + { + line: '\\in', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.relation.mathjax' } + ] + } + ], + [ + { + line: '\\therefore', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.relation.mathjax' } + ] + } + ], + + // --- Accents --- + [ + { + line: '\\hat', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.accent.mathjax' } + ] + } + ], + [ + { + line: '\\vec', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.accent.mathjax' } + ] + } + ], + [ + { + line: '\\overbrace', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.accent.mathjax' } + ] + } + ], + [ + { + // Capitalized accent variant + line: '\\Hat', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.accent.mathjax' } + ] + } + ], + + // --- Arrows --- + [ + { + line: '\\rightarrow', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.arrow.mathjax' } + ] + } + ], + [ + { + line: '\\Leftrightarrow', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.arrow.mathjax' } + ] + } + ], + [ + { + line: '\\mapsto', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.arrow.mathjax' } + ] + } + ], + [ + { + line: '\\implies', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.arrow.mathjax' } + ] + } + ], + [ + { + line: '\\iff', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.arrow.mathjax' } + ] + } + ], + + // --- Sizing / style --- + [ + { + line: '\\left', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.sizing.mathjax' } + ] + } + ], + [ + { + line: '\\displaystyle', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.sizing.mathjax' } + ] + } + ], + [ + { + line: '\\bigg', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.sizing.mathjax' } + ] + } + ], + + // --- Named delimiters --- + [ + { + line: '\\langle', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.delimiter.mathjax' } + ] + } + ], + [ + { + line: '\\rfloor', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.delimiter.mathjax' } + ] + } + ], + [ + { + line: '\\Vert', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.delimiter.mathjax' } + ] + } + ], + + // --- Spacing --- + [ + { + line: '\\quad', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.spacing.mathjax' } + ] + } + ], + [ + { + line: '\\qquad', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.spacing.mathjax' } + ] + } + ], + + // --- Font commands + argument --- + [ + { + line: '\\text{hello}', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.font.mathjax' }, + { startIndex: 5, type: 'delimiter.curly.mathjax' }, + { startIndex: 6, type: 'string.mathjax' }, + { startIndex: 11, type: 'delimiter.curly.mathjax' } + ] + } + ], + [ + { + line: '\\mathbb{R}', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.font.mathjax' }, + { startIndex: 7, type: 'delimiter.curly.mathjax' }, + { startIndex: 8, type: 'string.mathjax' }, + { startIndex: 9, type: 'delimiter.curly.mathjax' } + ] + } + ], + [ + { + // Nested braces inside font argument + line: '\\text{f(x)}', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.font.mathjax' }, + { startIndex: 5, type: 'delimiter.curly.mathjax' }, + { startIndex: 6, type: 'string.mathjax' }, + { startIndex: 10, type: 'delimiter.curly.mathjax' } + ] + } + ], + + // --- Misc symbols --- + [ + { + line: '\\infty', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + [ + { + line: '\\forall', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + [ + { + line: '\\cdot', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + [ + { + line: '\\oplus', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + [ + { + line: '\\ldots', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + + // --- Unknown/catch-all command --- + [ + { + line: '\\myCustomMacro', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.mathjax' } + ] + } + ], + + // --- Prefix ambiguity: \in vs \infty vs \int --- + [ + { + // \int must not match as \in + t + line: '\\int', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.operator.mathjax' } + ] + } + ], + [ + { + // \infty must not match as \in + fy + line: '\\infty', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'constant.symbol.mathjax' } + ] + } + ], + [ + { + // \lim must not swallow \limsup or \liminf + line: '\\limsup', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'support.function.mathjax' } + ] + } + ], + [ + { + // \subset must not shadow \subseteq + line: '\\subseteq', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.relation.mathjax' } + ] + } + ], + + // --- Multi-token expression: quadratic formula --- + [ + { + line: 'x = \\frac{-b}{2a}', + tokens: [ + { startIndex: 0, type: 'variable.mathjax' }, + { startIndex: 1, type: '' }, + { startIndex: 2, type: 'operator.mathjax' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'keyword.control.mathjax' }, + { startIndex: 5, type: 'keyword.operator.mathjax' }, + { startIndex: 9, type: 'delimiter.curly.mathjax' }, + { startIndex: 10, type: 'operator.mathjax' }, + { startIndex: 11, type: 'variable.mathjax' }, + { startIndex: 12, type: 'delimiter.curly.mathjax' }, + { startIndex: 14, type: 'number.mathjax' }, + { startIndex: 15, type: 'variable.mathjax' }, + { startIndex: 16, type: 'delimiter.curly.mathjax' } + ] + } + ], + + // --- Multi-token expression: integral --- + // \int_0^1 f(x)\, dx + // 01234567890123456789 + [ + { + line: '\\int_0^1 f(x)\\, dx', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, // \ + { startIndex: 1, type: 'keyword.operator.mathjax' }, // int + { startIndex: 5, type: 'number.mathjax' }, // 0 (_4 merged into int token by Monarch) + { startIndex: 6, type: 'keyword.operator.mathjax' }, // ^ + { startIndex: 7, type: 'number.mathjax' }, // 1 + { startIndex: 8, type: '' }, // (space) + { startIndex: 9, type: 'variable.mathjax' }, // f + { startIndex: 10, type: 'delimiter.parenthesis.mathjax' }, // ( + { startIndex: 11, type: 'variable.mathjax' }, // x + { startIndex: 12, type: 'delimiter.parenthesis.mathjax' }, // ) + { startIndex: 13, type: 'keyword.mathjax' }, // \, + { startIndex: 15, type: '' }, // (space) + { startIndex: 16, type: 'variable.mathjax' } // dx (merged) + ] + } + ], + + // --- Multi-line: sum across two lines --- + // \sum_{n=0}^{\infty} + // 0123456789012345678 9 + [ + { + line: '\\sum_{n=0}^{\\infty}', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, // \ + { startIndex: 1, type: 'keyword.operator.mathjax' }, // sum + { startIndex: 5, type: 'delimiter.curly.mathjax' }, // { (_4 merged by Monarch) + { startIndex: 6, type: 'variable.mathjax' }, // n + { startIndex: 7, type: 'operator.mathjax' }, // = + { startIndex: 8, type: 'number.mathjax' }, // 0 + { startIndex: 9, type: 'delimiter.curly.mathjax' }, // } + { startIndex: 10, type: 'keyword.operator.mathjax' }, // ^ + { startIndex: 11, type: 'delimiter.curly.mathjax' }, // { + { startIndex: 12, type: 'keyword.control.mathjax' }, // \ + { startIndex: 13, type: 'constant.symbol.mathjax' }, // infty + { startIndex: 18, type: 'delimiter.curly.mathjax' } // } + ] + }, + { + // \frac{1}{n^2} + // 0123456789012 3 + line: '\\frac{1}{n^2}', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, // \ + { startIndex: 1, type: 'keyword.operator.mathjax' }, // frac + { startIndex: 5, type: 'delimiter.curly.mathjax' }, // { + { startIndex: 6, type: 'number.mathjax' }, // 1 + { startIndex: 7, type: 'delimiter.curly.mathjax' }, // } + { startIndex: 9, type: 'variable.mathjax' }, // n ({ at 8 merged into }) + { startIndex: 10, type: 'keyword.operator.mathjax' }, // ^ + { startIndex: 11, type: 'number.mathjax' }, // 2 + { startIndex: 12, type: 'delimiter.curly.mathjax' } // } + ] + } + ], + + // --- \left \right with delimiter --- + [ + { + line: '\\left( x \\right)', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.sizing.mathjax' }, + { startIndex: 5, type: 'delimiter.parenthesis.mathjax' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'variable.mathjax' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'keyword.control.mathjax' }, + { startIndex: 10, type: 'keyword.sizing.mathjax' }, + { startIndex: 15, type: 'delimiter.parenthesis.mathjax' } + ] + } + ], + + // --- \text{} state does not persist across expressions --- + [ + { + line: '\\text{for all} x', + tokens: [ + { startIndex: 0, type: 'keyword.control.mathjax' }, + { startIndex: 1, type: 'keyword.font.mathjax' }, + { startIndex: 5, type: 'delimiter.curly.mathjax' }, + { startIndex: 6, type: 'string.mathjax' }, + { startIndex: 13, type: 'delimiter.curly.mathjax' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'variable.mathjax' } + ] + } + ], +]); diff --git a/src/languages/definitions/mathjax/mathjax.ts b/src/languages/definitions/mathjax/mathjax.ts new file mode 100644 index 0000000000..950ccc3103 --- /dev/null +++ b/src/languages/definitions/mathjax/mathjax.ts @@ -0,0 +1,486 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { languages } from '../../../editor'; + +export const conf: languages.LanguageConfiguration = { + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' } + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' } + ], + comments: { + lineComment: '%' + } +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.mathjax', + + // Greek letters (lowercase, uppercase, variants) and Hebrew letters + greekLetters: [ + 'alpha', + 'beta', + 'chi', + 'delta', + 'epsilon', + 'eta', + 'gamma', + 'iota', + 'kappa', + 'lambda', + 'mu', + 'nu', + 'omega', + 'phi', + 'pi', + 'psi', + 'rho', + 'sigma', + 'tau', + 'theta', + 'upsilon', + 'xi', + 'zeta', + 'Delta', + 'Gamma', + 'Lambda', + 'Omega', + 'Phi', + 'Pi', + 'Psi', + 'Sigma', + 'Theta', + 'Upsilon', + 'Xi', + // variants + 'varepsilon', + 'varphi', + 'varpi', + 'varrho', + 'varsigma', + 'vartheta', + 'varkappa', + 'digamma', + // Hebrew + 'aleph', + 'beth', + 'gimel', + 'daleth' + ], + + // Named math functions (rendered upright) + mathFunctions: [ + 'arccos', + 'arcsin', + 'arctan', + 'cos', + 'cosh', + 'cot', + 'coth', + 'csc', + 'deg', + 'det', + 'dim', + 'exp', + 'gcd', + 'hom', + 'inf', + 'ker', + 'lg', + 'lim', + 'liminf', + 'limsup', + 'ln', + 'log', + 'max', + 'min', + 'Pr', + 'sec', + 'sin', + 'sinh', + 'sup', + 'tan', + 'tanh', + 'arg' + ], + + // Structural/large operators + mathOperators: [ + 'frac', + 'sqrt', + 'sum', + 'prod', + 'coprod', + 'int', + 'iint', + 'iiint', + 'iiiint', + 'oint', + 'partial', + 'nabla', + 'bigcap', + 'bigcup', + 'biguplus', + 'bigoplus', + 'bigotimes', + 'bigodot', + 'bigvee', + 'bigwedge', + 'bigsqcup' + ], + + // Relational symbols + mathRelations: [ + 'leq', + 'geq', + 'neq', + 'approx', + 'equiv', + 'cong', + 'sim', + 'simeq', + 'propto', + 'subset', + 'supset', + 'subseteq', + 'supseteq', + 'sqsubset', + 'sqsubseteq', + 'sqsupset', + 'sqsupseteq', + 'in', + 'notin', + 'ni', + 'prec', + 'succ', + 'preceq', + 'succeq', + 'll', + 'gg', + 'perp', + 'mid', + 'parallel', + 'vdash', + 'dashv', + 'models', + 'bowtie', + 'smile', + 'frown', + 'asymp', + 'doteq', + 'approxeq', + 'thicksim', + 'triangleq', + 'therefore', + 'because' + ], + + // Math mode accents and decorations + mathAccents: [ + 'bar', + 'hat', + 'tilde', + 'dot', + 'ddot', + 'vec', + 'acute', + 'grave', + 'breve', + 'check', + 'widehat', + 'widetilde', + 'overline', + 'underline', + 'overbrace', + 'underbrace', + 'overrightarrow', + 'overleftarrow', + 'Bar', + 'Hat', + 'Tilde', + 'Dot', + 'Ddot', + 'Vec', + 'Acute', + 'Grave', + 'Breve', + 'Check' + ], + + // Arrow symbols + mathArrows: [ + 'leftarrow', + 'rightarrow', + 'Rightarrow', + 'leftrightarrow', + 'Leftarrow', + 'ReRightarrow', + 'Leftrightarrow', + 'longleftarrow', + 'longrightarrow', + 'longleftrightarrow', + 'Longleftarrow', + 'Longrightarrow', + 'Longleftrightarrow', + 'uparrow', + 'downarrow', + 'updownarrow', + 'Uparrow', + 'Downarrow', + 'Updownarrow', + 'mapsto', + 'longmapsto', + 'nearrow', + 'searrow', + 'swarrow', + 'nwarrow', + 'hookleftarrow', + 'hookrightarrow', + 'leftharpoonup', + 'leftharpoondown', + 'rightharpoonup', + 'rightharpoondown', + 'rightleftharpoons', + 'leftrightharpoons', + 'curvearrowleft', + 'curvearrowright', + 'to', + 'gets', + 'implies', + 'iff' + ], + + // Delimiter sizing and math style commands + mathSizing: [ + 'left', + 'right', + 'big', + 'Big', + 'bigg', + 'Bigg', + 'bigl', + 'bigr', + 'bigm', + 'displaystyle', + 'textstyle', + 'scriptstyle', + 'scriptscriptstyle' + ], + + // Named delimiter symbols + mathDelimiters: [ + 'langle', + 'rangle', + 'lfloor', + 'rfloor', + 'lceil', + 'rceil', + 'lbrace', + 'rbrace', + 'vert', + 'Vert', + 'llcorner', + 'lrcorner', + 'ulcorner', + 'urcorner' + ], + + // Font/style commands + mathFonts: [ + 'mathrm', + 'mathbf', + 'mathit', + 'mathsf', + 'mathtt', + 'mathcal', + 'mathfrak', + 'mathbb', + 'mathscr', + 'text', + 'textrm', + 'textit', + 'textbf' + ], + + // Spacing commands + mathSpacing: [ + 'quad', + 'qquad', + 'hspace', + 'mspace', + 'mkern', + 'thinspace', + 'negthinspace' + ], + + // Miscellaneous math symbols + mathSymbols: [ + 'infty', + 'emptyset', + 'varnothing', + 'prime', + 'backprime', + 'cdot', + 'times', + 'div', + 'pm', + 'mp', + 'circ', + 'bullet', + 'star', + 'ast', + 'dagger', + 'ddagger', + 'oplus', + 'ominus', + 'otimes', + 'oslash', + 'odot', + 'diamond', + 'wr', + 'amalg', + 'cap', + 'cup', + 'setminus', + 'land', + 'lor', + 'neg', + 'forall', + 'exists', + 'nexists', + 'ldots', + 'cdots', + 'vdots', + 'ddots', + 'hbar', + 'hslash', + 'ell', + 'wp', + 'Re', + 'Im', + 'angle', + 'measuredangle', + 'triangle', + 'surd', + 'clubsuit', + 'diamondsuit', + 'heartsuit', + 'spadesuit', + 'eth', + 'sharp', + 'flat', + 'natural', + 'top', + 'bot', + 'complement' + ], + + tokenizer: { + root: [ + // Whitespace and comments + { include: '@whitespace' }, + + // Double backslash (line break in math) + [/\\\\/, 'keyword'], + + // Named commands — check against each category in priority order + [ + /(\\)((?:arc(?:cos|sin|tan)|(?:cos|sin|tan|sec|csc|cot)h?|limsup|liminf|lim|log|ln|lg|exp|max|min|sup|inf|det|deg|dim|gcd|ker|hom|arg|Pr))(?![a-zA-Z])/, + ['keyword.control', 'support.function'] + ], + [ + /(\\)((?:iiiint|iiint|iint|oint|int|frac|sqrt|sum|prod|coprod|partial|nabla|bigsqcup|biguplus|bigotimes|bigodot|bigoplus|bigwedge|bigvee|bigcup|bigcap))(?![a-zA-Z])/, + ['keyword.control', 'keyword.operator'] + ], + [ + /(\\)((?:sqsubseteq|sqsupseteq|sqsubset|sqsupset|subseteq|supseteq|subset|supset|approxeq|thicksim|triangleq|therefore|because|parallel|preceq|succeq|propto|approx|models|dashv|vdash|bowtie|notin|equiv|simeq|asymp|doteq|frown|smile|prec|succ|geq|leq|neq|cong|sim|mid|gg|ll|ni|in))(?![a-zA-Z])/, + ['keyword.control', 'keyword.relation'] + ], + [ + /(\\)((?:overleftarrow|overrightarrow|underbrace|overbrace|underline|overline|widetilde|widehat|breve|check|grave|acute|tilde|ddot|dot|vec|bar|hat|Bar|Hat|Tilde|Dot|Ddot|Vec|Acute|Grave|Breve|Check))(?![a-zA-Z])/, + ['keyword.control', 'keyword.accent'] + ], + [ + /(\\)((?:longleftrightarrow|longrightarrow|longleftarrow|Longleftrightarrow|Longrightarrow|Longleftarrow|leftrightharpoons|rightleftharpoons|leftharpoondown|rightharpoondown|leftharpoonup|rightharpoonup|curvearrowright|curvearrowleft|hookrightarrow|hookleftarrow|Leftrightarrow|leftrightarrow|updownarrow|Updownarrow|longmapsto|Rightarrow|Leftarrow|rightarrow|leftarrow|Downarrow|downarrow|searrow|nearrow|swarrow|nwarrow|mapsto|Uparrow|uparrow|implies|gets|iff|to))(?![a-zA-Z])/, + ['keyword.control', 'keyword.arrow'] + ], + [ + /(\\)((?:scriptscriptstyle|displaystyle|scriptstyle|textstyle|bigg|Bigg|bigl|bigr|bigm|Big|big|left|right))(?![a-zA-Z])/, + ['keyword.control', 'keyword.sizing'] + ], + [ + /(\\)((?:llcorner|lrcorner|ulcorner|urcorner|langle|rangle|lfloor|rfloor|lceil|rceil|lbrace|rbrace|Vert|vert))(?![a-zA-Z])/, + ['keyword.control', 'keyword.delimiter'] + ], + [ + /(\\)((?:mathrm|mathbf|mathit|mathsf|mathtt|mathcal|mathfrak|mathscr|mathbb|textrm|textit|textbf|text))(?![a-zA-Z])/, + [{ token: 'keyword.control' }, { token: 'keyword.font', next: '@mathFontArg' }] + ], + [ + /(\\)((?:negthinspace|thinspace|qquad|quad|hspace|mspace|mkern))(?![a-zA-Z])/, + ['keyword.control', 'keyword.spacing'] + ], + [ + /(\\)((?:measuredangle|complement|varnothing|backprime|clubsuit|diamondsuit|heartsuit|spadesuit|nexists|diamond|dagger|ddagger|bullet|setminus|natural|ldots|cdots|vdots|ddots|hslash|angle|surd|sharp|flat|times|infty|prime|exists|forall|amalg|emptyset|ominus|otimes|oslash|oplus|odot|hbar|cdot|land|neg|div|lor|ast|cup|cap|bot|top|ell|eth|wr|Im|Re|wp|pm|mp|star|circ))(?![a-zA-Z])/, + ['keyword.control', 'constant.symbol'] + ], + [ + /(\\)((?:varepsilon|varkappa|varsigma|vartheta|digamma|varpi|varrho|varphi|Upsilon|upsilon|daleth|aleph|alpha|delta|gamma|kappa|sigma|theta|omega|Delta|Gamma|iota|Lambda|Omega|Sigma|Theta|Upsilon|lambda|beta|gimel|beth|eta|zeta|chi|phi|rho|tau|mu|nu|pi|xi|Phi|Psi|Xi|Pi))(?![a-zA-Z])/, + ['keyword.control', 'constant.greek'] + ], + + // Catch-all named command + [/(\\)([a-zA-Z]+)/, ['keyword.control', 'keyword']], + + // Single-char commands: \ + non-letter + [/\\[^a-zA-Z]/, 'keyword'], + + // Brackets + [/[{}()\[\]]/, '@brackets'], + + // Sub/superscript, alignment + [/[_^&]/, 'keyword.operator'], + + // Standard operators + [/[+\-/*=<>!,;|]/, 'operator'], + + // Numbers + [/\d+(\.\d+)?/, 'number'], + + // Single-letter math variables + [/[a-zA-Z]/, 'variable'], + ], + + whitespace: [ + [/[ \t\r\n]+/, ''], + [/%.*$/, 'comment'], + ], + + // Captures the argument to font commands like \text{...} as plain text + mathFontArg: [ + [/\s+/, ''], + [/\{/, { token: 'delimiter.curly', next: '@mathFontArgContent' }], + ['', '', '@pop'], + ], + + mathFontArgContent: [ + [/[^{}]+/, 'string'], + [/\{/, { token: 'delimiter.curly', next: '@mathFontArgContent' }], + [/\}/, { token: 'delimiter.curly', next: '@pop' }], + ], + } +}; diff --git a/src/languages/definitions/mathjax/register.ts b/src/languages/definitions/mathjax/register.ts new file mode 100644 index 0000000000..395048751e --- /dev/null +++ b/src/languages/definitions/mathjax/register.ts @@ -0,0 +1,13 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerLanguage } from '../_.contribution'; + +registerLanguage({ + id: 'mathjax', + extensions: ['.mjax'], + aliases: ['MathJax', 'mathjax'], + loader: () => import('./mathjax') +}); diff --git a/src/languages/definitions/register.all.ts b/src/languages/definitions/register.all.ts index ff00612225..fcb591a52b 100644 --- a/src/languages/definitions/register.all.ts +++ b/src/languages/definitions/register.all.ts @@ -33,12 +33,14 @@ import './java/register'; import './javascript/register'; import './julia/register'; import './kotlin/register'; +import './latex/register'; import './less/register'; import './lexon/register'; import './lua/register'; import './liquid/register'; import './m3/register'; import './markdown/register'; +import './mathjax/register'; import './mdx/register'; import './mips/register'; import './msdax/register'; diff --git a/website/src/website/data/home-samples/sample.latex.txt b/website/src/website/data/home-samples/sample.latex.txt new file mode 100644 index 0000000000..e30cd8795b --- /dev/null +++ b/website/src/website/data/home-samples/sample.latex.txt @@ -0,0 +1,68 @@ +\documentclass[12pt,a4paper]{article} +\usepackage[utf8]{inputenc} +\usepackage{amsmath, amssymb, graphicx} + +% This is a LaTeX sample document + +\title{A Sample \LaTeX{} Document} +\author{Jane Doe} +\date{\today} + +\newcommand{\R}{\mathbb{R}} +\newcommand{\norm}[1]{\left\| #1 \right\|} + +\begin{document} + +\maketitle + +\begin{abstract} +This document demonstrates \textbf{bold}, \textit{italic}, +and \texttt{monospace} text formatting in \LaTeX{}. +\end{abstract} + +\section{Introduction} +Let $f: \R \to \R$ be a continuous function. The equation +holds for all $x \in \R$: +\begin{equation} + \int_{-\infty}^{\infty} e^{-x^2}\, dx = \sqrt{\pi} +\end{equation} + +\subsection{Mathematics} +Display math uses double dollar signs: +$$ + \sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6} +$$ + +\section{Lists} +\begin{itemize} + \item First item with \emph{emphasis} + \item Second item: \hspace{1.5em} indented gap + \item Third item referencing~\cite{knuth1984} +\end{itemize} + +\section{Figures and Tables} +\begin{figure}[htbp] + \centering + \includegraphics[width=0.8\textwidth]{example-image} + \caption{An example figure.} + \label{fig:example} +\end{figure} + +See Figure~\ref{fig:example} for details. + +\begin{table}[htbp] + \centering + \begin{tabular}{|l|c|r|} + \hline + Left & Center & Right \\ + \hline + 1 & 2 & 3 \\ + \hline + \end{tabular} + \caption{A simple table.} +\end{table} + +\bibliography{references} +\bibliographystyle{plain} + +\end{document} diff --git a/website/src/website/data/home-samples/sample.mathjax.txt b/website/src/website/data/home-samples/sample.mathjax.txt new file mode 100644 index 0000000000..f490e16964 --- /dev/null +++ b/website/src/website/data/home-samples/sample.mathjax.txt @@ -0,0 +1,34 @@ +% Euler's identity +e^{i\pi} + 1 = 0 + +% Gaussian integral +\int_{-\infty}^{\infty} e^{-x^2}\, dx = \sqrt{\pi} + +% Taylor series +\sum_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!} (x - a)^n + +% Matrix norm +\left\| A \right\|_2 = \sqrt{\lambda_{\max}(A^* A)} + +% Stokes' theorem +\oint_{\partial \Omega} \omega = \int_{\Omega} d\omega + +% Cauchy-Schwarz inequality +\left| \sum_{k=1}^{n} a_k b_k \right|^2 + \leq \left( \sum_{k=1}^{n} a_k^2 \right) + \left( \sum_{k=1}^{n} b_k^2 \right) + +% Quadratic formula +x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} + +% Greek letters and arrows +\alpha, \beta, \gamma \in \mathbb{R} +\quad \Rightarrow \quad +f(\alpha) \leq f(\beta) + \nabla f(\beta)^\top (\alpha - \beta) + +% Matrix +A = \begin{pmatrix} + a_{11} & a_{12} \\ + a_{21} & a_{22} +\end{pmatrix}, \quad +\det(A) = a_{11}a_{22} - a_{12}a_{21}