tokens.mjs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /* Hand-written tokenizer for LaTeX. */
  2. import { ExternalTokenizer, ContextTracker } from '@lezer/lr'
  3. import {
  4. LiteralArgContent,
  5. SpaceDelimitedLiteralArgContent,
  6. VerbContent,
  7. VerbatimContent,
  8. LstInlineContent,
  9. Begin,
  10. End,
  11. KnownEnvironment,
  12. Csname,
  13. TrailingWhitespaceOnly,
  14. TrailingContent,
  15. RefCtrlSeq,
  16. RefStarrableCtrlSeq,
  17. CiteCtrlSeq,
  18. CiteStarrableCtrlSeq,
  19. LabelCtrlSeq,
  20. MathTextCtrlSeq,
  21. HboxCtrlSeq,
  22. TitleCtrlSeq,
  23. AuthorCtrlSeq,
  24. AffilCtrlSeq,
  25. AffiliationCtrlSeq,
  26. DateCtrlSeq,
  27. DocumentClassCtrlSeq,
  28. UsePackageCtrlSeq,
  29. HrefCtrlSeq,
  30. UrlCtrlSeq,
  31. VerbCtrlSeq,
  32. LstInlineCtrlSeq,
  33. IncludeGraphicsCtrlSeq,
  34. IncludeSvgCtrlSeq,
  35. CaptionCtrlSeq,
  36. DefCtrlSeq,
  37. LetCtrlSeq,
  38. LeftCtrlSeq,
  39. RightCtrlSeq,
  40. NewCommandCtrlSeq,
  41. RenewCommandCtrlSeq,
  42. NewEnvironmentCtrlSeq,
  43. RenewEnvironmentCtrlSeq,
  44. DocumentEnvName,
  45. TabularEnvName,
  46. EquationEnvName,
  47. EquationArrayEnvName,
  48. VerbatimEnvName,
  49. TikzPictureEnvName,
  50. FigureEnvName,
  51. OpenParenCtrlSym,
  52. CloseParenCtrlSym,
  53. OpenBracketCtrlSym,
  54. CloseBracketCtrlSym,
  55. LineBreakCtrlSym,
  56. // Sectioning commands
  57. BookCtrlSeq,
  58. PartCtrlSeq,
  59. ChapterCtrlSeq,
  60. SectionCtrlSeq,
  61. SubSectionCtrlSeq,
  62. SubSubSectionCtrlSeq,
  63. ParagraphCtrlSeq,
  64. SubParagraphCtrlSeq,
  65. InputCtrlSeq,
  66. IncludeCtrlSeq,
  67. SubfileCtrlSeq,
  68. ItemCtrlSeq,
  69. NewTheoremCtrlSeq,
  70. TheoremStyleCtrlSeq,
  71. BibliographyCtrlSeq,
  72. BibliographyStyleCtrlSeq,
  73. CenteringCtrlSeq,
  74. ListEnvName,
  75. MaketitleCtrlSeq,
  76. TextColorCtrlSeq,
  77. ColorBoxCtrlSeq,
  78. HLineCtrlSeq,
  79. TopRuleCtrlSeq,
  80. MidRuleCtrlSeq,
  81. BottomRuleCtrlSeq,
  82. TableEnvName,
  83. MultiColumnCtrlSeq,
  84. ParBoxCtrlSeq,
  85. // Marker for end of argument lists
  86. endOfArguments,
  87. hasMoreArguments,
  88. hasMoreArgumentsOrOptionals,
  89. endOfArgumentsAndOptionals,
  90. TextBoldCtrlSeq,
  91. TextItalicCtrlSeq,
  92. TextSmallCapsCtrlSeq,
  93. TextTeletypeCtrlSeq,
  94. TextMediumCtrlSeq,
  95. TextSansSerifCtrlSeq,
  96. TextSuperscriptCtrlSeq,
  97. TextSubscriptCtrlSeq,
  98. TextStrikeOutCtrlSeq,
  99. EmphasisCtrlSeq,
  100. UnderlineCtrlSeq,
  101. SetLengthCtrlSeq,
  102. FootnoteCtrlSeq,
  103. EndnoteCtrlSeq,
  104. } from './latex.terms.mjs'
  105. const MAX_ARGUMENT_LOOKAHEAD = 100
  106. function nameChar(ch) {
  107. // we accept A-Z a-z 0-9 * + @ in environment names
  108. return (
  109. (ch >= 65 && ch <= 90) ||
  110. (ch >= 97 && ch <= 122) ||
  111. (ch >= 48 && ch <= 57) ||
  112. ch === 42 ||
  113. ch === 43 ||
  114. ch === 64
  115. )
  116. }
  117. // match [a-zA-Z]
  118. function alphaChar(ch) {
  119. return (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)
  120. }
  121. let cachedName = null
  122. let cachedInput = null
  123. let cachedPos = 0
  124. function envNameAfter(input, offset) {
  125. const pos = input.pos + offset
  126. if (cachedInput === input && cachedPos === pos) {
  127. return cachedName
  128. }
  129. if (input.peek(offset) !== '{'.charCodeAt(0)) return
  130. offset++
  131. let name = ''
  132. for (;;) {
  133. const next = input.peek(offset)
  134. if (!nameChar(next)) break
  135. name += String.fromCharCode(next)
  136. offset++
  137. }
  138. cachedInput = input
  139. cachedPos = pos
  140. return (cachedName = name || null)
  141. }
  142. function ElementContext(name, parent) {
  143. this.name = name
  144. this.parent = parent
  145. this.hash = parent ? parent.hash : 0
  146. for (let i = 0; i < name.length; i++)
  147. this.hash +=
  148. (this.hash << 4) + name.charCodeAt(i) + (name.charCodeAt(i) << 8)
  149. }
  150. export const elementContext = new ContextTracker({
  151. start: null,
  152. shift(context, term, stack, input) {
  153. return term === Begin
  154. ? new ElementContext(envNameAfter(input, '\\begin'.length) || '', context)
  155. : context
  156. },
  157. reduce(context, term) {
  158. return term === KnownEnvironment && context ? context.parent : context
  159. },
  160. reuse(context, node, _stack, input) {
  161. const type = node.type.id
  162. return type === Begin
  163. ? new ElementContext(envNameAfter(input, 0) || '', context)
  164. : context
  165. },
  166. hash(context) {
  167. return context ? context.hash : 0
  168. },
  169. strict: false,
  170. })
  171. // tokenizer for \verb|...| commands
  172. export const verbTokenizer = new ExternalTokenizer(
  173. (input, stack) => {
  174. if (input.next === '*'.charCodeAt(0)) input.advance()
  175. const delimiter = input.next
  176. if (delimiter === -1) return // hit end of file
  177. if (/\s|\*/.test(String.fromCharCode(delimiter))) return // invalid delimiter
  178. input.advance()
  179. for (;;) {
  180. const next = input.next
  181. if (next === -1 || next === CHAR_NEWLINE) return
  182. input.advance()
  183. if (next === delimiter) break
  184. }
  185. return input.acceptToken(VerbContent)
  186. },
  187. { contextual: false }
  188. )
  189. // tokenizer for \lstinline|...| commands
  190. export const lstinlineTokenizer = new ExternalTokenizer(
  191. (input, stack) => {
  192. let delimiter = input.next
  193. if (delimiter === -1) return // hit end of file
  194. if (/\s/.test(String.fromCharCode(delimiter))) {
  195. return // invalid delimiter
  196. }
  197. if (delimiter === CHAR_OPEN_BRACE) {
  198. delimiter = CHAR_CLOSE_BRACE
  199. }
  200. input.advance()
  201. for (;;) {
  202. const next = input.next
  203. if (next === -1 || next === CHAR_NEWLINE) return
  204. input.advance()
  205. if (next === delimiter) break
  206. }
  207. return input.acceptToken(LstInlineContent)
  208. },
  209. { contextual: false }
  210. )
  211. const matchForward = (input, expected, offset = 0) => {
  212. for (let i = 0; i < expected.length; i++) {
  213. if (String.fromCharCode(input.peek(offset + i)) !== expected[i]) {
  214. return false
  215. }
  216. }
  217. return true
  218. }
  219. // tokenizer for \begin{verbatim}...\end{verbatim} environments
  220. export const verbatimTokenizer = new ExternalTokenizer(
  221. (input, stack) => {
  222. const delimiter = '\\end{' + stack.context.name + '}'
  223. for (let offset = 0; ; offset++) {
  224. const next = input.peek(offset)
  225. if (next === -1 || matchForward(input, delimiter, offset)) {
  226. return input.acceptToken(VerbatimContent, offset)
  227. }
  228. }
  229. },
  230. { contextual: false }
  231. )
  232. // tokenizer for \href{...} and similar commands
  233. export const literalArgTokenizer = new ExternalTokenizer(
  234. input => {
  235. for (let offset = 0; ; offset++) {
  236. const next = input.peek(offset)
  237. if (next === -1 || next === CHAR_CLOSE_BRACE) {
  238. return input.acceptToken(LiteralArgContent, offset)
  239. }
  240. }
  241. },
  242. { contextual: false }
  243. )
  244. // tokenizer for literal content delimited by whitespace, such as in `\input foo.tex`
  245. export const spaceDelimitedLiteralArgTokenizer = new ExternalTokenizer(
  246. input => {
  247. for (let offset = 0; ; offset++) {
  248. const next = input.peek(offset)
  249. if (next === -1 || next === CHAR_SPACE || next === CHAR_NEWLINE) {
  250. return input.acceptToken(SpaceDelimitedLiteralArgContent, offset)
  251. }
  252. }
  253. },
  254. { contextual: false }
  255. )
  256. // helper function to look up charCodes
  257. function _char(s) {
  258. return s.charCodeAt(0)
  259. }
  260. const CHAR_BACKSLASH = _char('\\')
  261. const CHAR_OPEN_BRACE = _char('{')
  262. const CHAR_OPEN_BRACKET = _char('[')
  263. const CHAR_CLOSE_BRACE = _char('}')
  264. const CHAR_TAB = _char('\t')
  265. const CHAR_SPACE = _char(' ')
  266. const CHAR_NEWLINE = _char('\n')
  267. const lookaheadTokenizer = getToken =>
  268. new ExternalTokenizer(
  269. input => {
  270. for (let i = 0; i < MAX_ARGUMENT_LOOKAHEAD; ++i) {
  271. const next = input.peek(i)
  272. if (next === CHAR_SPACE || next === CHAR_TAB) {
  273. continue
  274. }
  275. const token = getToken(next)
  276. if (token) {
  277. input.acceptToken(token)
  278. return
  279. }
  280. }
  281. },
  282. { contextual: false, fallback: true }
  283. )
  284. export const argumentListTokenizer = lookaheadTokenizer(next => {
  285. if (next === CHAR_OPEN_BRACE) {
  286. return hasMoreArguments
  287. } else {
  288. return endOfArguments
  289. }
  290. })
  291. export const argumentListWithOptionalTokenizer = lookaheadTokenizer(next => {
  292. if (next === CHAR_OPEN_BRACE || next === CHAR_OPEN_BRACKET) {
  293. return hasMoreArgumentsOrOptionals
  294. } else {
  295. return endOfArgumentsAndOptionals
  296. }
  297. })
  298. const CHAR_AT_SYMBOL = _char('@')
  299. export const csnameTokenizer = new ExternalTokenizer((input, stack) => {
  300. let offset = 0
  301. let end = -1
  302. // look at the first character, we are looking for acceptable control sequence names
  303. // including @ signs, \\[a-zA-Z@]+
  304. const next = input.peek(offset)
  305. if (next === -1) {
  306. return
  307. }
  308. // reject anything not starting with a backslash,
  309. // we only accept control sequences
  310. if (next !== CHAR_BACKSLASH) {
  311. return
  312. }
  313. offset++
  314. for (;;) {
  315. const next = input.peek(offset)
  316. // stop when we reach the end of file or a non-csname character
  317. if (next === -1 || !(alphaChar(next) || next === CHAR_AT_SYMBOL)) {
  318. end = offset - 1
  319. break
  320. }
  321. end = offset
  322. offset++
  323. }
  324. if (end === -1) return
  325. // accept the content as a valid control sequence
  326. return input.acceptToken(Csname, end + 1)
  327. })
  328. const END_DOCUMENT_MARK = '\\end{document}'.split('').reverse()
  329. export const trailingContentTokenizer = new ExternalTokenizer(
  330. (input, stack) => {
  331. if (input.next === -1) return // no trailing content
  332. // Look back for end-document mark, bail out if any characters do not match
  333. for (let i = 1; i < END_DOCUMENT_MARK.length + 1; i++) {
  334. if (String.fromCharCode(input.peek(-i)) !== END_DOCUMENT_MARK[i - 1]) {
  335. return
  336. }
  337. }
  338. while (input.next === CHAR_SPACE || input.next === CHAR_NEWLINE) {
  339. const next = input.advance()
  340. if (next === -1) return input.acceptToken(TrailingWhitespaceOnly) // trailing whitespace only
  341. }
  342. // accept the all content up to the end of the document
  343. while (input.advance() !== -1) {
  344. //
  345. }
  346. return input.acceptToken(TrailingContent)
  347. }
  348. )
  349. const refCommands = new Set([
  350. '\\fullref',
  351. '\\Vref',
  352. '\\autopageref',
  353. '\\autoref',
  354. '\\eqref',
  355. '\\labelcpageref',
  356. '\\labelcref',
  357. '\\lcnamecref',
  358. '\\lcnamecrefs',
  359. '\\namecref',
  360. '\\nameCref',
  361. '\\namecrefs',
  362. '\\nameCrefs',
  363. '\\thnameref',
  364. '\\thref',
  365. '\\titleref',
  366. '\\vrefrange',
  367. '\\Crefrange',
  368. '\\Crefrang',
  369. '\\fref',
  370. '\\pref',
  371. '\\tref',
  372. '\\Aref',
  373. '\\Bref',
  374. '\\Pref',
  375. '\\Sref',
  376. '\\vref',
  377. '\\nameref',
  378. ])
  379. const refStarrableCommands = new Set([
  380. '\\vpageref',
  381. '\\vref',
  382. '\\zcpageref',
  383. '\\zcref',
  384. '\\zfullref',
  385. '\\zref',
  386. '\\zvpageref',
  387. '\\zvref',
  388. '\\cref',
  389. '\\Cref',
  390. '\\pageref',
  391. '\\ref',
  392. '\\Ref',
  393. '\\subref',
  394. '\\zpageref',
  395. '\\ztitleref',
  396. '\\vpagerefrange',
  397. '\\zvpagerefrange',
  398. '\\zvrefrange',
  399. '\\crefrange',
  400. ])
  401. const citeCommands = new Set([
  402. '\\autocites',
  403. '\\Autocites',
  404. '\\Cite',
  405. '\\citeA',
  406. '\\citealp',
  407. '\\Citealp',
  408. '\\citealt',
  409. '\\Citealt',
  410. '\\citeauthorNP',
  411. '\\citeauthorp',
  412. '\\Citeauthorp',
  413. '\\citeauthort',
  414. '\\Citeauthort',
  415. '\\citeNP',
  416. '\\citenum',
  417. '\\citen',
  418. '\\citeonline',
  419. '\\cites',
  420. '\\Cites',
  421. '\\citeurl',
  422. '\\citeyearpar',
  423. '\\defcitealias',
  424. '\\fnotecite',
  425. '\\footcite',
  426. '\\footcitetext',
  427. '\\footfullcite',
  428. '\\footnotecites',
  429. '\\Footnotecites',
  430. '\\fullcite',
  431. '\\fullciteA',
  432. '\\fullciteauthor',
  433. '\\fullciteauthorNP',
  434. '\\maskcite',
  435. '\\maskciteA',
  436. '\\maskcitealp',
  437. '\\maskCitealp',
  438. '\\maskcitealt',
  439. '\\maskCitealt',
  440. '\\maskciteauthor',
  441. '\\maskciteauthorNP',
  442. '\\maskciteauthorp',
  443. '\\maskCiteauthorp',
  444. '\\maskciteauthort',
  445. '\\maskCiteauthort',
  446. '\\maskciteNP',
  447. '\\maskcitenum',
  448. '\\maskcitep',
  449. '\\maskCitep',
  450. '\\maskcitepalias',
  451. '\\maskcitet',
  452. '\\maskCitet',
  453. '\\maskcitetalias',
  454. '\\maskciteyear',
  455. '\\maskciteyearNP',
  456. '\\maskciteyearpar',
  457. '\\maskfullcite',
  458. '\\maskfullciteA',
  459. '\\maskfullciteauthor',
  460. '\\maskfullciteauthorNP',
  461. '\\masknocite',
  462. '\\maskshortcite',
  463. '\\maskshortciteA',
  464. '\\maskshortciteauthor',
  465. '\\maskshortciteauthorNP',
  466. '\\maskshortciteNP',
  467. '\\mautocite',
  468. '\\Mautocite',
  469. '\\mcite',
  470. '\\Mcite',
  471. '\\mfootcite',
  472. '\\mfootcitetext',
  473. '\\mparencite',
  474. '\\Mparencite',
  475. '\\msupercite',
  476. '\\mtextcite',
  477. '\\Mtextcite',
  478. '\\nocite',
  479. '\\nocitemeta',
  480. '\\notecite',
  481. '\\Parencite',
  482. '\\parencites',
  483. '\\Parencites',
  484. '\\pnotecite',
  485. '\\shortcite',
  486. '\\shortciteA',
  487. '\\shortciteauthor',
  488. '\\shortciteauthorNP',
  489. '\\shortciteNP',
  490. '\\smartcite',
  491. '\\Smartcite',
  492. '\\smartcites',
  493. '\\Smartcites',
  494. '\\supercite',
  495. '\\supercites',
  496. '\\textcite',
  497. '\\Textcite',
  498. '\\textcites',
  499. '\\Textcites',
  500. ])
  501. const citeStarredCommands = new Set([
  502. '\\cite',
  503. '\\citeauthor',
  504. '\\Citeauthor',
  505. '\\citedate',
  506. '\\citep',
  507. '\\citepalias',
  508. '\\Citep',
  509. '\\citetitle',
  510. '\\citeyear',
  511. '\\parencite',
  512. '\\citet',
  513. '\\citetalias',
  514. '\\autocite',
  515. '\\Autocite',
  516. ])
  517. const labelCommands = new Set(['\\label', '\\thlabel', '\\zlabel'])
  518. const mathTextCommands = new Set(['\\text', '\\tag', '\\textrm', '\\intertext'])
  519. const otherKnowncommands = {
  520. '\\hbox': HboxCtrlSeq,
  521. '\\title': TitleCtrlSeq,
  522. '\\author': AuthorCtrlSeq,
  523. '\\affil': AffilCtrlSeq,
  524. '\\affiliation': AffiliationCtrlSeq,
  525. '\\date': DateCtrlSeq,
  526. '\\documentclass': DocumentClassCtrlSeq,
  527. '\\usepackage': UsePackageCtrlSeq,
  528. '\\href': HrefCtrlSeq,
  529. '\\url': UrlCtrlSeq,
  530. '\\verb': VerbCtrlSeq,
  531. '\\lstinline': LstInlineCtrlSeq,
  532. '\\includegraphics': IncludeGraphicsCtrlSeq,
  533. '\\includesvg': IncludeSvgCtrlSeq,
  534. '\\caption': CaptionCtrlSeq,
  535. '\\def': DefCtrlSeq,
  536. '\\let': LetCtrlSeq,
  537. '\\left': LeftCtrlSeq,
  538. '\\right': RightCtrlSeq,
  539. '\\newcommand': NewCommandCtrlSeq,
  540. '\\renewcommand': RenewCommandCtrlSeq,
  541. '\\newenvironment': NewEnvironmentCtrlSeq,
  542. '\\renewenvironment': RenewEnvironmentCtrlSeq,
  543. '\\book': BookCtrlSeq,
  544. '\\part': PartCtrlSeq,
  545. '\\addpart': PartCtrlSeq,
  546. '\\chapter': ChapterCtrlSeq,
  547. '\\addchap': ChapterCtrlSeq,
  548. '\\section': SectionCtrlSeq,
  549. '\\addseq': SectionCtrlSeq,
  550. '\\subsection': SubSectionCtrlSeq,
  551. '\\subsubsection': SubSubSectionCtrlSeq,
  552. '\\paragraph': ParagraphCtrlSeq,
  553. '\\subparagraph': SubParagraphCtrlSeq,
  554. '\\input': InputCtrlSeq,
  555. '\\include': IncludeCtrlSeq,
  556. '\\subfile': SubfileCtrlSeq,
  557. '\\item': ItemCtrlSeq,
  558. '\\centering': CenteringCtrlSeq,
  559. '\\newtheorem': NewTheoremCtrlSeq,
  560. '\\theoremstyle': TheoremStyleCtrlSeq,
  561. '\\bibliography': BibliographyCtrlSeq,
  562. '\\bibliographystyle': BibliographyStyleCtrlSeq,
  563. '\\maketitle': MaketitleCtrlSeq,
  564. '\\textcolor': TextColorCtrlSeq,
  565. '\\colorbox': ColorBoxCtrlSeq,
  566. '\\hline': HLineCtrlSeq,
  567. '\\toprule': TopRuleCtrlSeq,
  568. '\\midrule': MidRuleCtrlSeq,
  569. '\\bottomrule': BottomRuleCtrlSeq,
  570. '\\multicolumn': MultiColumnCtrlSeq,
  571. '\\parbox': ParBoxCtrlSeq,
  572. '\\textbf': TextBoldCtrlSeq,
  573. '\\textit': TextItalicCtrlSeq,
  574. '\\textsc': TextSmallCapsCtrlSeq,
  575. '\\texttt': TextTeletypeCtrlSeq,
  576. '\\textmd': TextMediumCtrlSeq,
  577. '\\textsf': TextSansSerifCtrlSeq,
  578. '\\textsuperscript': TextSuperscriptCtrlSeq,
  579. '\\textsubscript': TextSubscriptCtrlSeq,
  580. '\\sout': TextStrikeOutCtrlSeq,
  581. '\\emph': EmphasisCtrlSeq,
  582. '\\underline': UnderlineCtrlSeq,
  583. '\\setlength': SetLengthCtrlSeq,
  584. '\\footnote': FootnoteCtrlSeq,
  585. '\\endnote': EndnoteCtrlSeq,
  586. }
  587. // specializer for control sequences
  588. // return new tokens for specific control sequences
  589. export const specializeCtrlSeq = (name, terms) => {
  590. if (name === '\\begin') return Begin
  591. if (name === '\\end') return End
  592. if (refCommands.has(name)) {
  593. return RefCtrlSeq
  594. }
  595. if (refStarrableCommands.has(name)) {
  596. return RefStarrableCtrlSeq
  597. }
  598. if (citeCommands.has(name)) {
  599. return CiteCtrlSeq
  600. }
  601. if (citeStarredCommands.has(name)) {
  602. return CiteStarrableCtrlSeq
  603. }
  604. if (labelCommands.has(name)) {
  605. return LabelCtrlSeq
  606. }
  607. if (mathTextCommands.has(name)) {
  608. return MathTextCtrlSeq
  609. }
  610. return otherKnowncommands[name] || -1
  611. }
  612. const tabularEnvNames = new Set([
  613. 'tabular',
  614. 'xltabular',
  615. 'tabularx',
  616. 'longtable',
  617. ])
  618. const equationEnvNames = new Set([
  619. 'equation',
  620. 'equation*',
  621. 'displaymath',
  622. 'displaymath*',
  623. 'math',
  624. 'math*',
  625. 'multline',
  626. 'multline*',
  627. 'matrix',
  628. 'tikzcd',
  629. ])
  630. const equationArrayEnvNames = new Set([
  631. 'array',
  632. 'eqnarray',
  633. 'eqnarray*',
  634. 'align',
  635. 'align*',
  636. 'alignat',
  637. 'alignat*',
  638. 'flalign',
  639. 'flalign*',
  640. 'gather',
  641. 'gather*',
  642. 'pmatrix',
  643. 'pmatrix*',
  644. 'bmatrix',
  645. 'bmatrix*',
  646. 'Bmatrix',
  647. 'Bmatrix*',
  648. 'vmatrix',
  649. 'vmatrix*',
  650. 'Vmatrix',
  651. 'Vmatrix*',
  652. 'smallmatrix',
  653. 'smallmatrix*',
  654. 'split',
  655. 'split*',
  656. 'gathered',
  657. 'gathered*',
  658. 'aligned',
  659. 'aligned*',
  660. 'alignedat',
  661. 'alignedat*',
  662. 'cases',
  663. 'cases*',
  664. 'dcases',
  665. 'dcases*',
  666. 'rcases',
  667. 'rcases*',
  668. 'IEEEeqnarray',
  669. 'IEEEeqnarray*',
  670. 'subeqnarray',
  671. 'subeqnarray*',
  672. ])
  673. const verbatimEnvNames = new Set([
  674. 'verbatim',
  675. 'boxedverbatim',
  676. 'lstlisting',
  677. 'minted',
  678. 'Verbatim',
  679. 'lstlisting',
  680. 'tcblisting',
  681. 'codeexample',
  682. 'comment',
  683. ])
  684. const otherKnownEnvNames = {
  685. document: DocumentEnvName,
  686. tikzpicture: TikzPictureEnvName,
  687. figure: FigureEnvName,
  688. 'figure*': FigureEnvName,
  689. subfigure: FigureEnvName,
  690. enumerate: ListEnvName,
  691. itemize: ListEnvName,
  692. table: TableEnvName,
  693. description: ListEnvName,
  694. }
  695. export const specializeEnvName = (name, terms) => {
  696. if (tabularEnvNames.has(name)) {
  697. return TabularEnvName
  698. }
  699. if (equationEnvNames.has(name)) {
  700. return EquationEnvName
  701. }
  702. if (equationArrayEnvNames.has(name)) {
  703. return EquationArrayEnvName
  704. }
  705. if (verbatimEnvNames.has(name)) {
  706. return VerbatimEnvName
  707. }
  708. return otherKnownEnvNames[name] || -1
  709. }
  710. const otherKnownCtrlSyms = {
  711. '\\(': OpenParenCtrlSym,
  712. '\\)': CloseParenCtrlSym,
  713. '\\[': OpenBracketCtrlSym,
  714. '\\]': CloseBracketCtrlSym,
  715. '\\\\': LineBreakCtrlSym,
  716. }
  717. export const specializeCtrlSym = (name, terms) => {
  718. return otherKnownCtrlSyms[name] || -1
  719. }