diff options
author | Andrey Makarov <ph.makarov@gmail.com> | 2021-04-15 09:12:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-15 08:12:44 +0200 |
commit | f8dce493d36c10bfdfb3bd4ac87eae7b96b97f1a (patch) | |
tree | 0b7408e8b11eda880ed55d67b3caae7f7205a977 /lib | |
parent | ae9231cfebf800886c4febcf0fc7ccc380066108 (diff) | |
download | Nim-f8dce493d36c10bfdfb3bd4ac87eae7b96b97f1a.tar.gz |
rst indentation fixes (ref #17340) (#17715)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/packages/docutils/rst.nim | 95 | ||||
-rw-r--r-- | lib/packages/docutils/rstast.nim | 18 |
2 files changed, 74 insertions, 39 deletions
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index c2385d517..7c4b92f88 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1532,6 +1532,55 @@ proc parseUntilNewline(p: var RstParser, father: PRstNode) = of tkEof, tkIndent: break proc parseSection(p: var RstParser, result: PRstNode) {.gcsafe.} + +proc tokenAfterNewline(p: RstParser, start: int): int = + result = start + while true: + case p.tok[result].kind + of tkEof: + break + of tkIndent: + inc result + break + else: inc result + +proc tokenAfterNewline(p: RstParser): int {.inline.} = + result = tokenAfterNewline(p, p.idx) + +proc getWrappableIndent(p: RstParser): int = + ## Gets baseline indentation for bodies of field lists and directives. + ## Handles situations like this (with possible de-indent in [case.3]):: + ## + ## :field: definition [case.1] + ## + ## currInd currentTok(p).col + ## | | + ## v v + ## + ## .. Note:: defItem: [case.2] + ## definition + ## + ## ^ + ## | + ## nextIndent + ## + ## .. Note:: - point1 [case.3] + ## - point 2 + ## + ## ^ + ## | + ## nextIndent + if currentTok(p).kind == tkIndent: + result = currentTok(p).ival + else: + var nextIndent = p.tok[tokenAfterNewline(p)-1].ival + if nextIndent <= currInd(p): # parse only this line [case.1] + result = currentTok(p).col + elif nextIndent >= currentTok(p).col: # may be a definition list [case.2] + result = currentTok(p).col + else: + result = nextIndent # [case.3] + proc parseField(p: var RstParser): PRstNode = ## Returns a parsed rnField node. ## @@ -1541,13 +1590,12 @@ proc parseField(p: var RstParser): PRstNode = var fieldname = newRstNode(rnFieldName) parseUntil(p, fieldname, ":", false) var fieldbody = newRstNode(rnFieldBody) - if currentTok(p).kind != tkIndent: parseLine(p, fieldbody) - if currentTok(p).kind == tkIndent: - var indent = currentTok(p).ival - if indent > col: - pushInd(p, indent) - parseSection(p, fieldbody) - popInd(p) + if currentTok(p).kind == tkWhite: inc p.idx + let indent = getWrappableIndent(p) + if indent > col: + pushInd(p, indent) + parseSection(p, fieldbody) + popInd(p) result.add(fieldname) result.add(fieldbody) @@ -1652,20 +1700,6 @@ proc countTitles(p: var RstParser, n: PRstNode) = if p.s.hTitleCnt >= 2: break -proc tokenAfterNewline(p: RstParser, start: int): int = - result = start - while true: - case p.tok[result].kind - of tkEof: - break - of tkIndent: - inc result - break - else: inc result - -proc tokenAfterNewline(p: RstParser): int {.inline.} = - result = tokenAfterNewline(p, p.idx) - proc isAdornmentHeadline(p: RstParser, adornmentIdx: int): bool = ## check that underline/overline length is enough for the heading. ## No support for Unicode. @@ -1752,7 +1786,7 @@ proc whichSection(p: RstParser): RstNodeKind = return rnCodeBlock elif currentTok(p).symbol == "::": return rnLiteralBlock - elif currentTok(p).symbol == ".." and predNL(p) and + elif currentTok(p).symbol == ".." and nextTok(p).kind in {tkWhite, tkIndent}: return rnDirective case currentTok(p).kind @@ -1780,10 +1814,9 @@ proc whichSection(p: RstParser): RstNodeKind = elif match(p, tokenAfterNewline(p), "aI") and isAdornmentHeadline(p, tokenAfterNewline(p)): result = rnHeadline - elif predNL(p) and - currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: + elif currentTok(p).symbol in ["+", "*", "-"] and nextTok(p).kind == tkWhite: result = rnBulletList - elif match(p, p.idx, ":w:E") and predNL(p): + elif match(p, p.idx, ":w:E"): # (currentTok(p).symbol == ":") result = rnFieldList elif match(p, p.idx, "(e) ") or match(p, p.idx, "e) ") or @@ -2350,9 +2383,11 @@ proc parseDirective(p: var RstParser, k: RstNodeKind, flags: DirFlags): PRstNode parseLine(p, args) result.add(args) if hasOptions in flags: - if currentTok(p).kind == tkIndent and currentTok(p).ival >= 3 and + if currentTok(p).kind == tkIndent and currentTok(p).ival > currInd(p) and nextTok(p).symbol == ":": + pushInd(p, currentTok(p).ival) options = parseFields(p) + popInd(p) result.add(options) proc indFollows(p: RstParser): bool = @@ -2363,11 +2398,9 @@ proc parseBlockContent(p: var RstParser, father: var PRstNode, ## parse the final content part of explicit markup blocks (directives, ## footnotes, etc). Returns true if succeeded. if currentTok(p).kind != tkIndent or indFollows(p): - var nextIndent = p.tok[tokenAfterNewline(p)-1].ival - if nextIndent <= currInd(p): # parse only this line - nextIndent = currentTok(p).col - pushInd(p, nextIndent) - var content = contentParser(p) + let blockIndent = getWrappableIndent(p) + pushInd(p, blockIndent) + let content = contentParser(p) popInd(p) father.add content result = true diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 394cc2698..00f3f2b35 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -350,7 +350,7 @@ proc renderRstToJson*(node: PRstNode): string = proc renderRstToStr*(node: PRstNode, indent=0): string = ## Writes the parsed RST `node` into a compact string ## representation in the format (one line per every sub-node): - ## ``indent - kind - text - level - order - anchor (if non-zero)`` + ## ``indent - kind - [text|level|order|adType] - anchor (if non-zero)`` ## (suitable for debugging of RST parsing). if node == nil: result.add " ".repeat(indent) & "[nil]\n" @@ -358,21 +358,23 @@ proc renderRstToStr*(node: PRstNode, indent=0): string = result.add " ".repeat(indent) & $node.kind case node.kind of rnLeaf, rnSmiley: - result.add (if node.text == "": "" else: "\t'" & node.text & "'") + result.add (if node.text == "": "" else: " '" & node.text & "'") of rnEnumList: - result.add "\tlabelFmt=" & node.labelFmt + result.add " labelFmt=" & node.labelFmt of rnLineBlockItem: var txt: string - if node.lineIndent == "\n": txt = "\t(blank line)" - else: txt = "\tlineIndent=" & $node.lineIndent.len + if node.lineIndent == "\n": txt = " (blank line)" + else: txt = " lineIndent=" & $node.lineIndent.len result.add txt + of rnAdmonition: + result.add " adType=" & node.adType of rnHeadline, rnOverline, rnMarkdownHeadline: - result.add "\tlevel=" & $node.level + result.add " level=" & $node.level of rnFootnote, rnCitation, rnFootnoteRef, rnOptionListItem: - result.add (if node.order == 0: "" else: "\torder=" & $node.order) + result.add (if node.order == 0: "" else: " order=" & $node.order) else: discard - result.add (if node.anchor == "": "" else: "\tanchor='" & node.anchor & "'") + result.add (if node.anchor == "": "" else: " anchor='" & node.anchor & "'") result.add "\n" for son in node.sons: result.add renderRstToStr(son, indent=indent+2) |