UNPKG

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