diff --git a/bikeshed/Spec.py b/bikeshed/Spec.py index b1c05d1787..c4af0bb9f0 100644 --- a/bikeshed/Spec.py +++ b/bikeshed/Spec.py @@ -185,7 +185,11 @@ def initMetadata(self, inputContent: InputSource.InputContent) -> None: m.retroactivelyCheckErrorLevel() def earlyParse(self, inputContent: InputSource.InputContent) -> list[l.Line]: - text = h.strFromNodes(h.initialDocumentParse(inputContent.content, h.ParseConfig.fromSpec(self)), withIlcc=True) + text = FIXMEreplaceMarkdownBlockquotes(inputContent.content) + nodes = h.initialDocumentParse(text, h.ParseConfig.fromSpec(self)) + if self.debug: + h.debugNodes(nodes) + text = h.strFromNodes(nodes, withIlcc=True) inputContent.rawLines = [x + "\n" for x in text.split("\n")] return inputContent.lines @@ -587,3 +591,35 @@ def checkForMixedIndents(lines: t.Sequence[l.Line], info: metadata.IndentInfo) - m.lint(f"Your document appears to use tabs to indent, but line {line.i} starts with spaces.") if re.match(r"(\t+ +\t)|( +\t)", line.text): m.lint(f"Line {line.i}'s indent contains tabs after spaces.") + + +def FIXMEreplaceMarkdownBlockquotes(text: str) -> str: + # Temporary hack to make the early HTML pass not be broken + # by Markdown blockquotes. + # * finds sequences of lines that share a ws + angle bracket prefix + # * replaces first such > with a blockquote-open PUA + # * replaces subsequent > with a space + # * adds a blockquote-close PUA to the end of last line + # * the HTML parser recognizes those PUAs and emits the correct start/end tags. + + lines = text.split("\n") + i = 0 + while True: + if i >= len(lines): + break + match = re.match(r"\s*>\s?", lines[i]) + if not match: + i += 1 + continue + if i + 1 < len(lines) and re.match(r"\s*>\s?", lines[i + 1]): + lines[i] = constants.bqStart + lines[i][len(match[0]) :] + i += 1 + while i < len(lines) and re.match(r"\s*>\s?", lines[i]): + match = re.match(r"\s*>\s?", lines[i]) + assert match is not None + lines[i] = lines[i][len(match[0]) :] + i += 1 + lines[i - 1] += constants.bqEnd + else: + i += 1 + return "\n".join(lines) diff --git a/bikeshed/config/__init__.py b/bikeshed/config/__init__.py index dbd1fe2101..c3fa29b525 100644 --- a/bikeshed/config/__init__.py +++ b/bikeshed/config/__init__.py @@ -32,6 +32,7 @@ intersperse, processTextNodes, reSubObject, + safeIndex, scriptPath, simplifyText, splitForValues, diff --git a/bikeshed/config/dfnTypes.py b/bikeshed/config/dfnTypes.py index b8602b1330..ee220b8055 100644 --- a/bikeshed/config/dfnTypes.py +++ b/bikeshed/config/dfnTypes.py @@ -53,7 +53,7 @@ dfnTypes = frozenset(list(dfnClassToType.values()) + ["dfn"]) maybeTypes = frozenset(["value", "type", "at-rule", "function", "selector"]) cssTypes = frozenset(["property", "value", "at-rule", "descriptor", "type", "function", "selector"]) -markupTypes = frozenset(["element", "element-attr", "element-state", "attr-value"]) +markupTypes = frozenset(["element", "element-attr", "element-state", "attr-value", "element-sub"]) idlTypes = frozenset( [ "event", diff --git a/bikeshed/config/main.py b/bikeshed/config/main.py index e065f7eb64..1ef0a2bd9a 100644 --- a/bikeshed/config/main.py +++ b/bikeshed/config/main.py @@ -192,3 +192,14 @@ def doEvery(s: float, action: t.Callable, lastTime: float | None = None) -> floa action() return newTime return lastTime + + +if t.TYPE_CHECKING: + SafeIndexDefaultT = t.TypeVar("SafeIndexDefaultT") + + +def safeIndex(coll: t.Sequence, needle: t.Any, default: SafeIndexDefaultT = None) -> int | SafeIndexDefaultT: # type: ignore[assignment] + try: + return coll.index(needle) + except ValueError: + return default diff --git a/bikeshed/constants.py b/bikeshed/constants.py index 98fae99b96..ed167b1e09 100644 --- a/bikeshed/constants.py +++ b/bikeshed/constants.py @@ -13,3 +13,5 @@ incrementLineCountChar = "\uebbd" decrementLineCountChar = "\uebbf" bsComment = "" +bqStart = "\uebc0" +bqEnd = "\uebc1" diff --git a/bikeshed/datablocks.py b/bikeshed/datablocks.py index b5d4039c08..9388b942bf 100644 --- a/bikeshed/datablocks.py +++ b/bikeshed/datablocks.py @@ -251,7 +251,7 @@ def transformPre(lines: list[str], tagName: str, firstLine: str, lineNum: int | def transformSimpleDef(lines: list[str], tagName: str, firstLine: str, lineNum: int | None, doc: t.SpecT) -> list[str]: - rows = parseDefBlock(lines, "simpledef", capitalizeKeys=False, doc=doc) + rows = parseDefBlock(lines, "simpledef", capitalizeKeys=False, doc=doc, lineNum=lineNum) lineNumAttr = "" if lineNum is not None: lineNumAttr = f" bs-line-number={lineNum}" @@ -268,7 +268,7 @@ def transformSimpleDef(lines: list[str], tagName: str, firstLine: str, lineNum: def transformPropdef(lines: list[str], tagName: str, firstLine: str, lineNum: int | None, doc: t.SpecT) -> list[str]: attrs: OrderedDict[str, str | None] = OrderedDict() - parsedAttrs = parseDefBlock(lines, "propdef", doc=doc) + parsedAttrs = parseDefBlock(lines, "propdef", doc=doc, lineNum=lineNum) # Displays entries in the order specified in attrs, # then if there are any unknown parsedAttrs values, # they're displayed afterward in the order they were specified. @@ -326,7 +326,10 @@ def transformPropdef(lines: list[str], tagName: str, firstLine: str, lineNum: in val = parsedAttrs[key] elif val is None: # Required key, not provided - m.die(f"The propdef for '{parsedAttrs.get('Name', '???')}' is missing a '{key}' line.", lineNum=lineNum) + if "Name" in parsedAttrs: + m.die(f"The propdef for '{parsedAttrs.get('Name', '')}' is missing a '{key}' line.", lineNum=lineNum) + else: + m.die(f"The propdef block is missing a '{key}' line.", lineNum=lineNum) continue else: # Optional key, just use default @@ -380,7 +383,7 @@ def transformDescdef(lines: list[str], tagName: str, firstLine: str, lineNum: in lineNumAttr = "" if lineNum is not None: lineNumAttr = f" bs-line-number={lineNum}" - vals = parseDefBlock(lines, "descdef", doc=doc) + vals = parseDefBlock(lines, "descdef", doc=doc, lineNum=lineNum) if "partial" in firstLine or "New values" in vals: requiredKeys = ["Name", "For"] ret = [ @@ -432,7 +435,7 @@ def transformElementdef(lines: list[str], tagName: str, firstLine: str, lineNum: if lineNum is not None: lineNumAttr = f" bs-line-number={lineNum}" attrs: OrderedDict[str, str | None] = OrderedDict() - parsedAttrs = parseDefBlock(lines, "elementdef", doc=doc) + parsedAttrs = parseDefBlock(lines, "elementdef", doc=doc, lineNum=lineNum) if "Attribute groups" in parsedAttrs or "Attributes" in parsedAttrs: html = "