diff --git a/bikeshed/markdown/markdown.py b/bikeshed/markdown/markdown.py index 186784c6df..779c487373 100644 --- a/bikeshed/markdown/markdown.py +++ b/bikeshed/markdown/markdown.py @@ -8,14 +8,14 @@ from ..messages import * -def parse(lines, numSpacesForIndentation, features=None, opaqueElements=None, blockElements=None): +def parse(lines, numSpacesForIndentation, features=None, opaqueElements=None, blockElements=None, itemNumContext=None): fromStrings = False if any(isinstance(l, str) for l in lines): fromStrings = True lines = [Line.Line(-1, l) for l in lines] lines = Line.rectify(lines) tokens = tokenizeLines(lines, numSpacesForIndentation, features, opaqueElements=opaqueElements, blockElements=blockElements) - html = parseTokens(tokens, numSpacesForIndentation) + html = parseTokens(tokens, numSpacesForIndentation, itemNumContext) if fromStrings: return [l.text for l in html] else: @@ -144,10 +144,10 @@ def inlineElementStart(line): elif re.match(r"((\*\s*){3,})$|((-\s*){3,})$|((_\s*){3,})$", line): token = {'type':'rule'} elif re.match(r"-?\d+\.\s", line): - match = re.match(r"(-?\d+)\.\s+(.*)", line) - token = {'type':'numbered', 'text': match.group(2), 'num': int(match.group(1))} + match = re.match(r"(-?\d+)\.\s+(\{#([^ }]+)\})?(\s+)?(.*)", line) + token = {'type':'numbered', 'text': match.group(5), 'num': int(match.group(1)), 'id': match.group(3)} elif re.match(r"-?\d+\.$", line): - token = {'type':'numbered', 'text': "", 'num': int(line[:-1])} + token = {'type':'numbered', 'text': "", 'num': int(line[:-1]), 'id': None} elif re.match(r"[*+-]\s", line): match = re.match(r"[*+-]\s+(.*)", line) token = {'type':'bulleted', 'text': match.group(1)} @@ -275,7 +275,7 @@ def stripPrefix(token, numSpacesForIndentation, len): return text[offset:] -def parseTokens(tokens, numSpacesForIndentation): +def parseTokens(tokens, numSpacesForIndentation, itemNumContext): ''' Token types: eof @@ -313,7 +313,7 @@ def parseTokens(tokens, numSpacesForIndentation): elif stream.currtype() == 'bulleted': lines += parseBulleted(stream) elif stream.currtype() == 'numbered': - lines += parseNumbered(stream, start=stream.currnum()) + lines += parseNumbered(stream, start=stream.currnum(), itemNumContext=itemNumContext) elif stream.currtype() in ("dt", "dd"): lines += parseDl(stream) elif stream.currtype() == "blockquote": @@ -456,7 +456,7 @@ def getItems(stream): return lines -def parseNumbered(stream, start=1): +def parseNumbered(stream, itemNumContext, start=1): prefixLen = stream.currprefixlen() ol_i = stream.currline().i numSpacesForIndentation = stream.numSpacesForIndentation @@ -466,18 +466,19 @@ def parseItem(stream): # Remove the numbered part from the line firstLine = stream.currtext() + "\n" i = stream.currline().i + id = stream.currid() lines = [lineFromStream(stream, firstLine)] while True: stream.advance() # All the conditions that indicate we're *past* the end of the item. if stream.currtype() == 'numbered' and stream.currprefixlen() == prefixLen: - return lines,i + return lines,i,id if stream.currprefixlen() < prefixLen: - return lines,i + return lines,i,id if stream.currtype() == 'blank' and stream.nexttype() != 'numbered' and stream.nextprefixlen() <= prefixLen: - return lines,i + return lines,i,id if stream.currtype() == 'eof': - return lines,i + return lines,i,id # Remove the prefix from each line before adding it. lines.append(lineFromStream(stream, stripPrefix(stream.curr(), numSpacesForIndentation, prefixLen + 1))) @@ -498,10 +499,18 @@ def getItems(stream): lines = [Line.Line(-1, "
    ".format(ol_i))] else: lines = [Line.Line(-1, "
      ".format(start, ol_i))] - for li_lines,i in getItems(stream): - lines.append(Line.Line(-1, "
    1. ".format(i))) - lines.extend(parse(li_lines, numSpacesForIndentation)) + for li_lines,i,id in getItems(stream): + itemNumInContext = None + if id is not None: + itemNumInContext = str(start) + if itemNumContext is not None: + itemNumInContext = itemNumContext + '.' + itemNumInContext + lines.append(Line.Line(-1, "
    2. ".format(i, escapeAttr(id), escapeAttr(itemNumInContext)))) + else: + lines.append(Line.Line(-1, "
    3. ".format(i))) + lines.extend(parse(li_lines, numSpacesForIndentation, itemNumContext=itemNumInContext)) lines.append(Line.Line(-1, "
    4. ")) + start += 1 lines.append(Line.Line(-1, "
    ")) return lines diff --git a/bikeshed/unsortedJunk.py b/bikeshed/unsortedJunk.py index fc8ddc5d48..19dfec44b6 100644 --- a/bikeshed/unsortedJunk.py +++ b/bikeshed/unsortedJunk.py @@ -369,9 +369,15 @@ def addVarClickHighlighting(doc): def fixIntraDocumentReferences(doc): ids = {el.get('id'):el for el in findAll("[id]", doc)} headingIDs = {el.get('id'):el for el in findAll("[id].heading", doc)} + stepIDs = {el.get('id'):el for el in findAll("li[id]", doc)} for el in findAll("a[href^='#']:not([href='#']):not(.self-link):not([data-link-type])", doc): targetID = urllib.parse.unquote(el.get("href")[1:]) - if el.get('data-section') is not None and targetID not in headingIDs: + if targetID in stepIDs and stepIDs[targetID].get('item') is not None: + li = stepIDs[targetID] + text = "step " + li.get('item') + appendChild(el, text) + continue + elif el.get('data-section') is not None and targetID not in headingIDs: die("Couldn't find target document section {0}:\n{1}", targetID, outerHTML(el), el=el) continue elif targetID not in ids: diff --git a/tests/step-links001.bs b/tests/step-links001.bs new file mode 100644 index 0000000000..8abd24b4a6 --- /dev/null +++ b/tests/step-links001.bs @@ -0,0 +1,19 @@ +
    +Title: Step-reference test
    +Group: test
    +Shortname: stepref
    +Level: 1
    +Status: LS
    +ED: https://example.com/stepref
    +Abstract: Testing step references
    +Editor: Bikeshed authors
    +Date: 2020-12-06
    +
    + +1. An Item. +1. {#foostep} An item with an id. + 1. A subitem. + 1. {#foostepbar} A subitem with an id. +1. Another item. +1. Reference [[#foostepbar]]. +1. Reference top-level [[#foostep]]. diff --git a/tests/step-links001.html b/tests/step-links001.html new file mode 100644 index 0000000000..76e6254741 --- /dev/null +++ b/tests/step-links001.html @@ -0,0 +1,434 @@ + + + + + Step-reference test + + + + + + + + +
    +

    +

    Step-reference test

    +

    Living Standard,

    +
    +
    +
    This version: +
    https://example.com/stepref +
    Editor: +
    Bikeshed authors +
    +
    +
    + +
    +
    +
    +

    Abstract

    +

    Testing step references

    +
    +
    + +
    +
      +
    1. +

      An Item.

      +
    2. +

      An item with an id.

      +
        +
      1. +

        A subitem.

        +
      2. +

        A subitem with an id.

        +
      +
    3. +

      Another item.

      +
    4. +

      Reference step 2.2.

      +
    5. +

      Reference top-level step 2.

      +
    +
    \ No newline at end of file