source: node_modules/highlight.js/lib/languages/latex.js@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/**
2 * @param {string} value
3 * @returns {RegExp}
4 * */
5
6/**
7 * @param {RegExp | string } re
8 * @returns {string}
9 */
10function source(re) {
11 if (!re) return null;
12 if (typeof re === "string") return re;
13
14 return re.source;
15}
16
17/**
18 * Any of the passed expresssions may match
19 *
20 * Creates a huge this | this | that | that match
21 * @param {(RegExp | string)[] } args
22 * @returns {string}
23 */
24function either(...args) {
25 const joined = '(' + args.map((x) => source(x)).join("|") + ")";
26 return joined;
27}
28
29/*
30Language: LaTeX
31Author: Benedikt Wilde <bwilde@posteo.de>
32Website: https://www.latex-project.org
33Category: markup
34*/
35
36/** @type LanguageFn */
37function latex(hljs) {
38 const KNOWN_CONTROL_WORDS = either(...[
39 '(?:NeedsTeXFormat|RequirePackage|GetIdInfo)',
40 'Provides(?:Expl)?(?:Package|Class|File)',
41 '(?:DeclareOption|ProcessOptions)',
42 '(?:documentclass|usepackage|input|include)',
43 'makeat(?:letter|other)',
44 'ExplSyntax(?:On|Off)',
45 '(?:new|renew|provide)?command',
46 '(?:re)newenvironment',
47 '(?:New|Renew|Provide|Declare)(?:Expandable)?DocumentCommand',
48 '(?:New|Renew|Provide|Declare)DocumentEnvironment',
49 '(?:(?:e|g|x)?def|let)',
50 '(?:begin|end)',
51 '(?:part|chapter|(?:sub){0,2}section|(?:sub)?paragraph)',
52 'caption',
53 '(?:label|(?:eq|page|name)?ref|(?:paren|foot|super)?cite)',
54 '(?:alpha|beta|[Gg]amma|[Dd]elta|(?:var)?epsilon|zeta|eta|[Tt]heta|vartheta)',
55 '(?:iota|(?:var)?kappa|[Ll]ambda|mu|nu|[Xx]i|[Pp]i|varpi|(?:var)rho)',
56 '(?:[Ss]igma|varsigma|tau|[Uu]psilon|[Pp]hi|varphi|chi|[Pp]si|[Oo]mega)',
57 '(?:frac|sum|prod|lim|infty|times|sqrt|leq|geq|left|right|middle|[bB]igg?)',
58 '(?:[lr]angle|q?quad|[lcvdi]?dots|d?dot|hat|tilde|bar)'
59 ].map(word => word + '(?![a-zA-Z@:_])'));
60 const L3_REGEX = new RegExp([
61 // A function \module_function_name:signature or \__module_function_name:signature,
62 // where both module and function_name need at least two characters and
63 // function_name may contain single underscores.
64 '(?:__)?[a-zA-Z]{2,}_[a-zA-Z](?:_?[a-zA-Z])+:[a-zA-Z]*',
65 // A variable \scope_module_and_name_type or \scope__module_ane_name_type,
66 // where scope is one of l, g or c, type needs at least two characters
67 // and module_and_name may contain single underscores.
68 '[lgc]__?[a-zA-Z](?:_?[a-zA-Z])*_[a-zA-Z]{2,}',
69 // A quark \q_the_name or \q__the_name or
70 // scan mark \s_the_name or \s__vthe_name,
71 // where variable_name needs at least two characters and
72 // may contain single underscores.
73 '[qs]__?[a-zA-Z](?:_?[a-zA-Z])+',
74 // Other LaTeX3 macro names that are not covered by the three rules above.
75 'use(?:_i)?:[a-zA-Z]*',
76 '(?:else|fi|or):',
77 '(?:if|cs|exp):w',
78 '(?:hbox|vbox):n',
79 '::[a-zA-Z]_unbraced',
80 '::[a-zA-Z:]'
81 ].map(pattern => pattern + '(?![a-zA-Z:_])').join('|'));
82 const L2_VARIANTS = [
83 {begin: /[a-zA-Z@]+/}, // control word
84 {begin: /[^a-zA-Z@]?/} // control symbol
85 ];
86 const DOUBLE_CARET_VARIANTS = [
87 {begin: /\^{6}[0-9a-f]{6}/},
88 {begin: /\^{5}[0-9a-f]{5}/},
89 {begin: /\^{4}[0-9a-f]{4}/},
90 {begin: /\^{3}[0-9a-f]{3}/},
91 {begin: /\^{2}[0-9a-f]{2}/},
92 {begin: /\^{2}[\u0000-\u007f]/}
93 ];
94 const CONTROL_SEQUENCE = {
95 className: 'keyword',
96 begin: /\\/,
97 relevance: 0,
98 contains: [
99 {
100 endsParent: true,
101 begin: KNOWN_CONTROL_WORDS
102 },
103 {
104 endsParent: true,
105 begin: L3_REGEX
106 },
107 {
108 endsParent: true,
109 variants: DOUBLE_CARET_VARIANTS
110 },
111 {
112 endsParent: true,
113 relevance: 0,
114 variants: L2_VARIANTS
115 }
116 ]
117 };
118 const MACRO_PARAM = {
119 className: 'params',
120 relevance: 0,
121 begin: /#+\d?/
122 };
123 const DOUBLE_CARET_CHAR = {
124 // relevance: 1
125 variants: DOUBLE_CARET_VARIANTS
126 };
127 const SPECIAL_CATCODE = {
128 className: 'built_in',
129 relevance: 0,
130 begin: /[$&^_]/
131 };
132 const MAGIC_COMMENT = {
133 className: 'meta',
134 begin: '% !TeX',
135 end: '$',
136 relevance: 10
137 };
138 const COMMENT = hljs.COMMENT(
139 '%',
140 '$',
141 {
142 relevance: 0
143 }
144 );
145 const EVERYTHING_BUT_VERBATIM = [
146 CONTROL_SEQUENCE,
147 MACRO_PARAM,
148 DOUBLE_CARET_CHAR,
149 SPECIAL_CATCODE,
150 MAGIC_COMMENT,
151 COMMENT
152 ];
153 const BRACE_GROUP_NO_VERBATIM = {
154 begin: /\{/, end: /\}/,
155 relevance: 0,
156 contains: ['self', ...EVERYTHING_BUT_VERBATIM]
157 };
158 const ARGUMENT_BRACES = hljs.inherit(
159 BRACE_GROUP_NO_VERBATIM,
160 {
161 relevance: 0,
162 endsParent: true,
163 contains: [BRACE_GROUP_NO_VERBATIM, ...EVERYTHING_BUT_VERBATIM]
164 }
165 );
166 const ARGUMENT_BRACKETS = {
167 begin: /\[/,
168 end: /\]/,
169 endsParent: true,
170 relevance: 0,
171 contains: [BRACE_GROUP_NO_VERBATIM, ...EVERYTHING_BUT_VERBATIM]
172 };
173 const SPACE_GOBBLER = {
174 begin: /\s+/,
175 relevance: 0
176 };
177 const ARGUMENT_M = [ARGUMENT_BRACES];
178 const ARGUMENT_O = [ARGUMENT_BRACKETS];
179 const ARGUMENT_AND_THEN = function(arg, starts_mode) {
180 return {
181 contains: [SPACE_GOBBLER],
182 starts: {
183 relevance: 0,
184 contains: arg,
185 starts: starts_mode
186 }
187 };
188 };
189 const CSNAME = function(csname, starts_mode) {
190 return {
191 begin: '\\\\' + csname + '(?![a-zA-Z@:_])',
192 keywords: {$pattern: /\\[a-zA-Z]+/, keyword: '\\' + csname},
193 relevance: 0,
194 contains: [SPACE_GOBBLER],
195 starts: starts_mode
196 };
197 };
198 const BEGIN_ENV = function(envname, starts_mode) {
199 return hljs.inherit(
200 {
201 begin: '\\\\begin(?=[ \t]*(\\r?\\n[ \t]*)?\\{' + envname + '\\})',
202 keywords: {$pattern: /\\[a-zA-Z]+/, keyword: '\\begin'},
203 relevance: 0,
204 },
205 ARGUMENT_AND_THEN(ARGUMENT_M, starts_mode)
206 );
207 };
208 const VERBATIM_DELIMITED_EQUAL = (innerName = "string") => {
209 return hljs.END_SAME_AS_BEGIN({
210 className: innerName,
211 begin: /(.|\r?\n)/,
212 end: /(.|\r?\n)/,
213 excludeBegin: true,
214 excludeEnd: true,
215 endsParent: true
216 });
217 };
218 const VERBATIM_DELIMITED_ENV = function(envname) {
219 return {
220 className: 'string',
221 end: '(?=\\\\end\\{' + envname + '\\})'
222 };
223 };
224
225 const VERBATIM_DELIMITED_BRACES = (innerName = "string") => {
226 return {
227 relevance: 0,
228 begin: /\{/,
229 starts: {
230 endsParent: true,
231 contains: [
232 {
233 className: innerName,
234 end: /(?=\})/,
235 endsParent:true,
236 contains: [
237 {
238 begin: /\{/,
239 end: /\}/,
240 relevance: 0,
241 contains: ["self"]
242 }
243 ],
244 }
245 ]
246 }
247 };
248 };
249 const VERBATIM = [
250 ...['verb', 'lstinline'].map(csname => CSNAME(csname, {contains: [VERBATIM_DELIMITED_EQUAL()]})),
251 CSNAME('mint', ARGUMENT_AND_THEN(ARGUMENT_M, {contains: [VERBATIM_DELIMITED_EQUAL()]})),
252 CSNAME('mintinline', ARGUMENT_AND_THEN(ARGUMENT_M, {contains: [VERBATIM_DELIMITED_BRACES(), VERBATIM_DELIMITED_EQUAL()]})),
253 CSNAME('url', {contains: [VERBATIM_DELIMITED_BRACES("link"), VERBATIM_DELIMITED_BRACES("link")]}),
254 CSNAME('hyperref', {contains: [VERBATIM_DELIMITED_BRACES("link")]}),
255 CSNAME('href', ARGUMENT_AND_THEN(ARGUMENT_O, {contains: [VERBATIM_DELIMITED_BRACES("link")]})),
256 ...[].concat(...['', '\\*'].map(suffix => [
257 BEGIN_ENV('verbatim' + suffix, VERBATIM_DELIMITED_ENV('verbatim' + suffix)),
258 BEGIN_ENV('filecontents' + suffix, ARGUMENT_AND_THEN(ARGUMENT_M, VERBATIM_DELIMITED_ENV('filecontents' + suffix))),
259 ...['', 'B', 'L'].map(prefix =>
260 BEGIN_ENV(prefix + 'Verbatim' + suffix, ARGUMENT_AND_THEN(ARGUMENT_O, VERBATIM_DELIMITED_ENV(prefix + 'Verbatim' + suffix)))
261 )
262 ])),
263 BEGIN_ENV('minted', ARGUMENT_AND_THEN(ARGUMENT_O, ARGUMENT_AND_THEN(ARGUMENT_M, VERBATIM_DELIMITED_ENV('minted')))),
264 ];
265
266 return {
267 name: 'LaTeX',
268 aliases: ['tex'],
269 contains: [
270 ...VERBATIM,
271 ...EVERYTHING_BUT_VERBATIM
272 ]
273 };
274}
275
276module.exports = latex;
Note: See TracBrowser for help on using the repository browser.