Merge pull request #18676 from overleaf/mj-web-linter-document-class

[web] Allow underscore in optional argument in \documentclass

GitOrigin-RevId: c6f8716548411ade03814c8123df76fa8aa70ecc
This commit is contained in:
Mathias Jakobsen 2024-06-07 12:05:49 +01:00 committed by Copybot
parent 2247f02308
commit f0eba8e742
4 changed files with 47 additions and 4 deletions

View file

@ -152,8 +152,7 @@ export const LaTeXLanguage = LRLanguage.define({
'HrefCommand/ShortTextArgument/ShortArg/...': t.link, 'HrefCommand/ShortTextArgument/ShortArg/...': t.link,
'HrefCommand/UrlArgument/...': t.monospace, 'HrefCommand/UrlArgument/...': t.monospace,
'CtrlSeq Csname': t.tagName, 'CtrlSeq Csname': t.tagName,
'DocumentClass/OptionalArgument/ShortOptionalArg/Normal': 'DocumentClass/OptionalArgument/ShortOptionalArg/...': t.attributeValue,
t.attributeValue,
'DocumentClass/ShortTextArgument/ShortArg/Normal': t.typeName, 'DocumentClass/ShortTextArgument/ShortArg/Normal': t.typeName,
'ListEnvironment/BeginEnv/OptionalArgument/...': t.monospace, 'ListEnvironment/BeginEnv/OptionalArgument/...': t.monospace,
Number: t.number, Number: t.number,

View file

@ -322,7 +322,7 @@ const read1filename = function (TokeniseResult, k) {
} }
} }
const readOptionalLabel = function (TokeniseResult, k) { const readOptionalArgumentWithUnderscores = function (TokeniseResult, k) {
// read a label my_label:text.. // read a label my_label:text..
const Tokens = TokeniseResult.tokens const Tokens = TokeniseResult.tokens
const text = TokeniseResult.text const text = TokeniseResult.text
@ -348,6 +348,7 @@ const readOptionalLabel = function (TokeniseResult, k) {
label = label + str label = label + str
if (str.match(/\]/)) { if (str.match(/\]/)) {
// breaking due to ] // breaking due to ]
j++
break break
} }
} else if (tok[1] === '_') { } else if (tok[1] === '_') {
@ -800,6 +801,31 @@ const InterpretTokens = function (TokeniseResult, ErrorReporter) {
) { ) {
// Environments.push({command: "end", name: "user-defined-equation", token: token}); // Environments.push({command: "end", name: "user-defined-equation", token: token});
seenUserDefinedEndEquation = true seenUserDefinedEndEquation = true
} else if (seq === 'documentclass') {
// try to read any optional params [LABEL].... allowing for
// underscores, advance if found
let newPos = readOptionalArgumentWithUnderscores(TokeniseResult, i)
if (newPos instanceof Error) {
TokenErrorFromTo(
Tokens[i + 1],
Tokens[Math.min(newPos.pos, len - 1)],
'invalid documentclass option'
)
i = newPos.pos
} else if (newPos == null) {
/* do nothing */
} else {
i = newPos
}
// Read parameter {....}, ignore if missing
newPos = readDefinition(TokeniseResult, i)
if (newPos === null) {
// NOTE: We could choose to throw an error here, as the argument is
// required. However, that would show errors as you are typing. So
// maybe it's better to be lenient.
} else {
i = newPos
}
} else if ( } else if (
seq === 'newcommand' || seq === 'newcommand' ||
seq === 'renewcommand' || seq === 'renewcommand' ||
@ -1038,7 +1064,7 @@ const InterpretTokens = function (TokeniseResult, ErrorReporter) {
} else if (seq === 'hyperref') { } else if (seq === 'hyperref') {
// try to read any optional params [LABEL].... allowing for // try to read any optional params [LABEL].... allowing for
// underscores, advance if found // underscores, advance if found
let newPos = readOptionalLabel(TokeniseResult, i) let newPos = readOptionalArgumentWithUnderscores(TokeniseResult, i)
if (newPos instanceof Error) { if (newPos instanceof Error) {
TokenErrorFromTo( TokenErrorFromTo(
Tokens[i + 1], Tokens[i + 1],

View file

@ -484,6 +484,7 @@ ShortOptionalArg {
( textBase ( textBase
| NonEmptyGroup<ShortOptionalArg> | NonEmptyGroup<ShortOptionalArg>
| "#" // macro character | "#" // macro character
| "_" // underscore is used in some parameter names
)* )*
} }

View file

@ -494,6 +494,23 @@ describe('LatexLinter', function () {
assert.equal(errors[0].text, 'unclosed group {') assert.equal(errors[0].text, 'unclosed group {')
}) })
it('should accept documentclass with no options', function () {
const { errors } = Parse('\\documentclass{article}')
assert.equal(errors.length, 0)
})
it('should accept documentclass with options', function () {
const { errors } = Parse('\\documentclass[a4paper]{article}')
assert.equal(errors.length, 0)
})
it('should accept documentclass with underscore in options', function () {
const { errors } = Parse(
'\\documentclass[my_custom_document_class_option]{my-custom-class}'
)
assert.equal(errors.length, 0)
})
// %novalidate // %novalidate
// %begin novalidate // %begin novalidate
// %end novalidate // %end novalidate