RST: implement internal targets (#16614)
This commit is contained in:
parent
335f849c36
commit
fd5c8ef208
6 changed files with 379 additions and 101 deletions
|
|
@ -560,7 +560,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var Rope, state: Runnab
|
||||||
"\n\\textbf{$1}\n", [msg.rope])
|
"\n\\textbf{$1}\n", [msg.rope])
|
||||||
inc d.listingCounter
|
inc d.listingCounter
|
||||||
let id = $d.listingCounter
|
let id = $d.listingCounter
|
||||||
dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"])
|
dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim", ""])
|
||||||
var dest2 = ""
|
var dest2 = ""
|
||||||
renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex)
|
renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex)
|
||||||
dest.add dest2
|
dest.add dest2
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,8 @@ $moduledesc
|
||||||
$content
|
$content
|
||||||
"""
|
"""
|
||||||
|
|
||||||
doc.listing_start = "<pre class=\"listing\">"
|
# $1 - number of listing in document, $2 - language (e.g. langNim), $3 - anchor
|
||||||
|
doc.listing_start = "<pre$3 class=\"listing\">"
|
||||||
doc.listing_end = "</pre>"
|
doc.listing_end = "</pre>"
|
||||||
|
|
||||||
# * $analytics: Google analytics location, includes <script> tags
|
# * $analytics: Google analytics location, includes <script> tags
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,19 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements a `reStructuredText`:idx: (RST) parser. A large
|
## ==================================
|
||||||
## subset is implemented. Some features of the `markdown`:idx: syntax are
|
## rst: Nim-flavored reStructuredText
|
||||||
## also supported. Nim can output the result to HTML (command ``rst2html``)
|
## ==================================
|
||||||
## or Latex (command ``rst2tex``).
|
##
|
||||||
|
## This module implements a `reStructuredText`:idx: (RST) parser.
|
||||||
|
## A large subset is implemented with some limitations_ and
|
||||||
|
## `Nim-specific features`_.
|
||||||
|
## A few `extra features`_ of the `Markdown`:idx: syntax are
|
||||||
|
## also supported.
|
||||||
|
##
|
||||||
|
## Nim can output the result to HTML (commands ``nim doc`` for
|
||||||
|
## ``*.nim`` files and ``nim rst2html`` for ``*.rst`` files) or
|
||||||
|
## Latex (command ``nim rst2tex`` for ``*.rst``).
|
||||||
##
|
##
|
||||||
## If you are new to RST please consider reading the following:
|
## If you are new to RST please consider reading the following:
|
||||||
##
|
##
|
||||||
|
|
@ -18,6 +27,9 @@
|
||||||
## 2) an `RST reference`_: a comprehensive cheatsheet for RST
|
## 2) an `RST reference`_: a comprehensive cheatsheet for RST
|
||||||
## 3) a more formal 50-page `RST specification`_.
|
## 3) a more formal 50-page `RST specification`_.
|
||||||
##
|
##
|
||||||
|
## Features
|
||||||
|
## --------
|
||||||
|
##
|
||||||
## Supported standard RST features:
|
## Supported standard RST features:
|
||||||
##
|
##
|
||||||
## * body elements
|
## * body elements
|
||||||
|
|
@ -43,27 +55,33 @@
|
||||||
## + comments
|
## + comments
|
||||||
## * inline markup
|
## * inline markup
|
||||||
## + *emphasis*, **strong emphasis**,
|
## + *emphasis*, **strong emphasis**,
|
||||||
## ``inline literals``, hyperlink references, substitution references,
|
## ``inline literals``, hyperlink references (including embedded URI),
|
||||||
## standalone hyperlinks
|
## substitution references, standalone hyperlinks,
|
||||||
|
## internal links (inline and outline)
|
||||||
## + \`interpreted text\` with roles ``:literal:``, ``:strong:``,
|
## + \`interpreted text\` with roles ``:literal:``, ``:strong:``,
|
||||||
## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:supscript:``
|
## ``emphasis``, ``:sub:``/``:subscript:``, ``:sup:``/``:supscript:``
|
||||||
## (see `RST roles list`_ for description).
|
## (see `RST roles list`_ for description).
|
||||||
|
## + inline internal targets
|
||||||
##
|
##
|
||||||
## Additional features:
|
## .. _`Nim-specific features`:
|
||||||
|
##
|
||||||
|
## Additional Nim-specific features:
|
||||||
##
|
##
|
||||||
## * directives: ``code-block``, ``title``, ``index``
|
## * directives: ``code-block``, ``title``, ``index``
|
||||||
## * ***triple emphasis*** (bold and italic) using \*\*\*
|
## * ***triple emphasis*** (bold and italic) using \*\*\*
|
||||||
## * ``:idx:`` role for \`interpreted text\` to include the link to this
|
## * ``:idx:`` role for \`interpreted text\` to include the link to this
|
||||||
## text into an index (example: `Nim index`_).
|
## text into an index (example: `Nim index`_).
|
||||||
##
|
##
|
||||||
|
## .. _`extra features`:
|
||||||
|
##
|
||||||
## Optional additional features, turned on by ``options: RstParseOption`` in
|
## Optional additional features, turned on by ``options: RstParseOption`` in
|
||||||
## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_:
|
## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_:
|
||||||
##
|
##
|
||||||
## * emoji / smiley symbols
|
## * emoji / smiley symbols
|
||||||
## * markdown tables
|
## * Markdown tables
|
||||||
## * markdown code blocks
|
## * Markdown code blocks
|
||||||
## * markdown links
|
## * Markdown links
|
||||||
## * markdown headlines
|
## * Markdown headlines
|
||||||
## * using ``1`` as auto-enumerator in enumerated lists like RST ``#``
|
## * using ``1`` as auto-enumerator in enumerated lists like RST ``#``
|
||||||
## (auto-enumerator ``1`` can not be used with ``#`` in the same list)
|
## (auto-enumerator ``1`` can not be used with ``#`` in the same list)
|
||||||
##
|
##
|
||||||
|
|
@ -73,7 +91,8 @@
|
||||||
## .. warning:: Using Nim-specific features can cause other RST implementations
|
## .. warning:: Using Nim-specific features can cause other RST implementations
|
||||||
## to fail on your document.
|
## to fail on your document.
|
||||||
##
|
##
|
||||||
## Limitations:
|
## Limitations
|
||||||
|
## -----------
|
||||||
##
|
##
|
||||||
## * no Unicode support in character width calculations
|
## * no Unicode support in character width calculations
|
||||||
## * body elements
|
## * body elements
|
||||||
|
|
@ -89,10 +108,21 @@
|
||||||
## - no ``role`` directives and no custom interpreted text roles
|
## - no ``role`` directives and no custom interpreted text roles
|
||||||
## - some standard roles are not supported (check `RST roles list`_)
|
## - some standard roles are not supported (check `RST roles list`_)
|
||||||
## - no footnotes & citations support
|
## - no footnotes & citations support
|
||||||
## - no inline internal targets
|
|
||||||
## * inline markup
|
## * inline markup
|
||||||
## - no simple-inline-markup
|
## - no simple-inline-markup
|
||||||
## - no embedded URI and aliases
|
## - no embedded aliases
|
||||||
|
##
|
||||||
|
## Usage
|
||||||
|
## -----
|
||||||
|
##
|
||||||
|
## See `Nim DocGen Tools Guide <docgen.html>`_ for the details about
|
||||||
|
## ``nim doc``, ``nim rst2html`` and ``nim rst2tex`` commands.
|
||||||
|
##
|
||||||
|
## See `packages/docutils/rstgen module <rstgen.html>`_ to know how to
|
||||||
|
## generate HTML or Latex strings to embed them into your documents.
|
||||||
|
##
|
||||||
|
## .. Tip:: Import ``packages/docutils/rst`` to use this module
|
||||||
|
## programmatically.
|
||||||
##
|
##
|
||||||
## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html
|
## .. _quick introduction: https://docutils.sourceforge.io/docs/user/rst/quickstart.html
|
||||||
## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html
|
## .. _RST reference: https://docutils.sourceforge.io/docs/user/rst/quickref.html
|
||||||
|
|
@ -100,13 +130,6 @@
|
||||||
## .. _RST directives list: https://docutils.sourceforge.io/docs/ref/rst/directives.html
|
## .. _RST directives list: https://docutils.sourceforge.io/docs/ref/rst/directives.html
|
||||||
## .. _RST roles list: https://docutils.sourceforge.io/docs/ref/rst/roles.html
|
## .. _RST roles list: https://docutils.sourceforge.io/docs/ref/rst/roles.html
|
||||||
## .. _Nim index: https://nim-lang.org/docs/theindex.html
|
## .. _Nim index: https://nim-lang.org/docs/theindex.html
|
||||||
##
|
|
||||||
## See `Nim DocGen Tools Guide <docgen.html>`_ for the details about
|
|
||||||
## ``nim doc``, ``nim rst2html`` and ``nim rst2tex`` commands.
|
|
||||||
##
|
|
||||||
## .. note:: Import ``packages/docutils/rst`` to use this module.
|
|
||||||
##
|
|
||||||
## See also `packages/docutils/rstgen module <rstgen.html>`_.
|
|
||||||
|
|
||||||
import
|
import
|
||||||
os, strutils, rstast
|
os, strutils, rstast
|
||||||
|
|
@ -118,7 +141,7 @@ type
|
||||||
roSupportSmilies, ## make the RST parser support smilies like ``:)``
|
roSupportSmilies, ## make the RST parser support smilies like ``:)``
|
||||||
roSupportRawDirective, ## support the ``raw`` directive (don't support
|
roSupportRawDirective, ## support the ``raw`` directive (don't support
|
||||||
## it for sandboxing)
|
## it for sandboxing)
|
||||||
roSupportMarkdown ## support additional features of markdown
|
roSupportMarkdown ## support additional features of Markdown
|
||||||
|
|
||||||
RstParseOptions* = set[RstParseOption]
|
RstParseOptions* = set[RstParseOption]
|
||||||
|
|
||||||
|
|
@ -131,7 +154,7 @@ type
|
||||||
meCannotOpenFile = "cannot open '$1'",
|
meCannotOpenFile = "cannot open '$1'",
|
||||||
meExpected = "'$1' expected",
|
meExpected = "'$1' expected",
|
||||||
meGridTableNotImplemented = "grid table is not implemented",
|
meGridTableNotImplemented = "grid table is not implemented",
|
||||||
meMarkdownIllformedTable = "illformed delimiter row of a markdown table",
|
meMarkdownIllformedTable = "illformed delimiter row of a Markdown table",
|
||||||
meNewSectionExpected = "new section expected",
|
meNewSectionExpected = "new section expected",
|
||||||
meGeneralParseError = "general parse error",
|
meGeneralParseError = "general parse error",
|
||||||
meInvalidDirective = "invalid directive: '$1'",
|
meInvalidDirective = "invalid directive: '$1'",
|
||||||
|
|
@ -379,12 +402,16 @@ type
|
||||||
Substitution = object
|
Substitution = object
|
||||||
key*: string
|
key*: string
|
||||||
value*: PRstNode
|
value*: PRstNode
|
||||||
|
AnchorSubst = tuple
|
||||||
|
mainAnchor: string
|
||||||
|
aliases: seq[string]
|
||||||
|
|
||||||
SharedState = object
|
SharedState = object
|
||||||
options: RstParseOptions # parsing options
|
options: RstParseOptions # parsing options
|
||||||
uLevel, oLevel: int # counters for the section levels
|
uLevel, oLevel: int # counters for the section levels
|
||||||
subs: seq[Substitution] # substitutions
|
subs: seq[Substitution] # substitutions
|
||||||
refs: seq[Substitution] # references
|
refs: seq[Substitution] # references
|
||||||
|
anchors: seq[AnchorSubst] # internal target substitutions
|
||||||
underlineToLevel: LevelMap # Saves for each possible title adornment
|
underlineToLevel: LevelMap # Saves for each possible title adornment
|
||||||
# character its level in the
|
# character its level in the
|
||||||
# current document.
|
# current document.
|
||||||
|
|
@ -405,6 +432,7 @@ type
|
||||||
filename*: string
|
filename*: string
|
||||||
line*, col*: int
|
line*, col*: int
|
||||||
hasToc*: bool
|
hasToc*: bool
|
||||||
|
curAnchor*: string # variable to track latest anchor in s.anchors
|
||||||
|
|
||||||
EParseError* = object of ValueError
|
EParseError* = object of ValueError
|
||||||
|
|
||||||
|
|
@ -577,6 +605,38 @@ proc findRef(p: var RstParser, key: string): PRstNode =
|
||||||
if key == p.s.refs[i].key:
|
if key == p.s.refs[i].key:
|
||||||
return p.s.refs[i].value
|
return p.s.refs[i].value
|
||||||
|
|
||||||
|
proc addAnchor(p: var RstParser, refn: string, reset: bool) =
|
||||||
|
## add anchor `refn` to anchor aliases and update last anchor ``curAnchor``
|
||||||
|
if p.curAnchor == "":
|
||||||
|
p.s.anchors.add (refn, @[refn])
|
||||||
|
else:
|
||||||
|
p.s.anchors[^1].mainAnchor = refn
|
||||||
|
p.s.anchors[^1].aliases.add refn
|
||||||
|
if reset:
|
||||||
|
p.curAnchor = ""
|
||||||
|
else:
|
||||||
|
p.curAnchor = refn
|
||||||
|
|
||||||
|
proc findMainAnchor(p: RstParser, refn: string): string =
|
||||||
|
for subst in p.s.anchors:
|
||||||
|
if subst.mainAnchor == refn: # no need to rename
|
||||||
|
result = subst.mainAnchor
|
||||||
|
break
|
||||||
|
var toLeave = false
|
||||||
|
for anchor in subst.aliases:
|
||||||
|
if anchor == refn: # this anchor will be named as mainAnchor
|
||||||
|
result = subst.mainAnchor
|
||||||
|
toLeave = true
|
||||||
|
if toLeave:
|
||||||
|
break
|
||||||
|
|
||||||
|
proc newRstNodeA(p: var RstParser, kind: RstNodeKind): PRstNode =
|
||||||
|
## create node and consume the current anchor
|
||||||
|
result = newRstNode(kind)
|
||||||
|
if p.curAnchor != "":
|
||||||
|
result.anchor = p.curAnchor
|
||||||
|
p.curAnchor = ""
|
||||||
|
|
||||||
proc newLeaf(p: var RstParser): PRstNode =
|
proc newLeaf(p: var RstParser): PRstNode =
|
||||||
result = newRstNode(rnLeaf, currentTok(p).symbol)
|
result = newRstNode(rnLeaf, currentTok(p).symbol)
|
||||||
|
|
||||||
|
|
@ -629,7 +689,10 @@ proc isInlineMarkupEnd(p: RstParser, markup: string): bool =
|
||||||
proc isInlineMarkupStart(p: RstParser, markup: string): bool =
|
proc isInlineMarkupStart(p: RstParser, markup: string): bool =
|
||||||
# rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
|
# rst rules: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
|
||||||
var d: char
|
var d: char
|
||||||
result = currentTok(p).symbol == markup
|
if markup != "_`":
|
||||||
|
result = currentTok(p).symbol == markup
|
||||||
|
else: # _` is a 2 token case
|
||||||
|
result = currentTok(p).symbol == "_" and nextTok(p).symbol == "`"
|
||||||
if not result: return
|
if not result: return
|
||||||
# Rule 6:
|
# Rule 6:
|
||||||
result = p.idx == 0 or prevTok(p).kind in {tkIndent, tkWhite} or
|
result = p.idx == 0 or prevTok(p).kind in {tkIndent, tkWhite} or
|
||||||
|
|
@ -873,7 +936,7 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
|
||||||
inc p.idx
|
inc p.idx
|
||||||
var lb = newRstNode(rnLiteralBlock)
|
var lb = newRstNode(rnLiteralBlock)
|
||||||
lb.add(n)
|
lb.add(n)
|
||||||
result = newRstNode(rnCodeBlock)
|
result = newRstNodeA(p, rnCodeBlock)
|
||||||
result.add(args)
|
result.add(args)
|
||||||
result.add(PRstNode(nil))
|
result.add(PRstNode(nil))
|
||||||
result.add(lb)
|
result.add(lb)
|
||||||
|
|
@ -918,6 +981,13 @@ proc parseInline(p: var RstParser, father: PRstNode) =
|
||||||
var n = newRstNode(rnEmphasis)
|
var n = newRstNode(rnEmphasis)
|
||||||
parseUntil(p, n, "*", true)
|
parseUntil(p, n, "*", true)
|
||||||
father.add(n)
|
father.add(n)
|
||||||
|
elif isInlineMarkupStart(p, "_`"):
|
||||||
|
var n = newRstNode(rnInlineTarget)
|
||||||
|
inc p.idx
|
||||||
|
parseUntil(p, n, "`", false)
|
||||||
|
let refn = rstnodeToRefname(n)
|
||||||
|
p.s.anchors.add (refn, @[refn])
|
||||||
|
father.add(n)
|
||||||
elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```":
|
elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```":
|
||||||
inc p.idx
|
inc p.idx
|
||||||
father.add(parseMarkdownCodeblock(p))
|
father.add(parseMarkdownCodeblock(p))
|
||||||
|
|
@ -1049,7 +1119,7 @@ proc parseFields(p: var RstParser): PRstNode =
|
||||||
if currentTok(p).kind == tkIndent and nextTok(p).symbol == ":" or
|
if currentTok(p).kind == tkIndent and nextTok(p).symbol == ":" or
|
||||||
atStart:
|
atStart:
|
||||||
var col = if atStart: currentTok(p).col else: currentTok(p).ival
|
var col = if atStart: currentTok(p).col else: currentTok(p).ival
|
||||||
result = newRstNode(rnFieldList)
|
result = newRstNodeA(p, rnFieldList)
|
||||||
if not atStart: inc p.idx
|
if not atStart: inc p.idx
|
||||||
while true:
|
while true:
|
||||||
result.add(parseField(p))
|
result.add(parseField(p))
|
||||||
|
|
@ -1090,7 +1160,7 @@ proc getArgument(n: PRstNode): string =
|
||||||
|
|
||||||
proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.}
|
proc parseDotDot(p: var RstParser): PRstNode {.gcsafe.}
|
||||||
proc parseLiteralBlock(p: var RstParser): PRstNode =
|
proc parseLiteralBlock(p: var RstParser): PRstNode =
|
||||||
result = newRstNode(rnLiteralBlock)
|
result = newRstNodeA(p, rnLiteralBlock)
|
||||||
var n = newRstNode(rnLeaf, "")
|
var n = newRstNode(rnLeaf, "")
|
||||||
if currentTok(p).kind == tkIndent:
|
if currentTok(p).kind == tkIndent:
|
||||||
var indent = currentTok(p).ival
|
var indent = currentTok(p).ival
|
||||||
|
|
@ -1248,7 +1318,7 @@ proc parseLineBlock(p: var RstParser): PRstNode =
|
||||||
result = nil
|
result = nil
|
||||||
if nextTok(p).kind in {tkWhite, tkIndent}:
|
if nextTok(p).kind in {tkWhite, tkIndent}:
|
||||||
var col = currentTok(p).col
|
var col = currentTok(p).col
|
||||||
result = newRstNode(rnLineBlock)
|
result = newRstNodeA(p, rnLineBlock)
|
||||||
while true:
|
while true:
|
||||||
var item = newRstNode(rnLineBlockItem)
|
var item = newRstNode(rnLineBlockItem)
|
||||||
if nextTok(p).kind == tkWhite:
|
if nextTok(p).kind == tkWhite:
|
||||||
|
|
@ -1314,6 +1384,7 @@ proc parseHeadline(p: var RstParser): PRstNode =
|
||||||
var c = nextTok(p).symbol[0]
|
var c = nextTok(p).symbol[0]
|
||||||
inc p.idx, 2
|
inc p.idx, 2
|
||||||
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
|
result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
|
||||||
|
addAnchor(p, rstnodeToRefname(result), reset=true)
|
||||||
|
|
||||||
type
|
type
|
||||||
IntSeq = seq[int]
|
IntSeq = seq[int]
|
||||||
|
|
@ -1349,7 +1420,7 @@ proc parseSimpleTable(p: var RstParser): PRstNode =
|
||||||
c: char
|
c: char
|
||||||
q: RstParser
|
q: RstParser
|
||||||
a, b: PRstNode
|
a, b: PRstNode
|
||||||
result = newRstNode(rnTable)
|
result = newRstNodeA(p, rnTable)
|
||||||
cols = @[]
|
cols = @[]
|
||||||
row = @[]
|
row = @[]
|
||||||
a = nil
|
a = nil
|
||||||
|
|
@ -1428,7 +1499,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode =
|
||||||
colNum: int
|
colNum: int
|
||||||
a, b: PRstNode
|
a, b: PRstNode
|
||||||
q: RstParser
|
q: RstParser
|
||||||
result = newRstNode(rnMarkdownTable)
|
result = newRstNodeA(p, rnMarkdownTable)
|
||||||
|
|
||||||
proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) =
|
proc parseRow(p: var RstParser, cellKind: RstNodeKind, result: PRstNode) =
|
||||||
row = readTableRow(p)
|
row = readTableRow(p)
|
||||||
|
|
@ -1452,7 +1523,7 @@ proc parseMarkdownTable(p: var RstParser): PRstNode =
|
||||||
parseRow(p, rnTableDataCell, result)
|
parseRow(p, rnTableDataCell, result)
|
||||||
|
|
||||||
proc parseTransition(p: var RstParser): PRstNode =
|
proc parseTransition(p: var RstParser): PRstNode =
|
||||||
result = newRstNode(rnTransition)
|
result = newRstNodeA(p, rnTransition)
|
||||||
inc p.idx
|
inc p.idx
|
||||||
if currentTok(p).kind == tkIndent: inc p.idx
|
if currentTok(p).kind == tkIndent: inc p.idx
|
||||||
if currentTok(p).kind == tkIndent: inc p.idx
|
if currentTok(p).kind == tkIndent: inc p.idx
|
||||||
|
|
@ -1475,13 +1546,14 @@ proc parseOverline(p: var RstParser): PRstNode =
|
||||||
if currentTok(p).kind == tkAdornment:
|
if currentTok(p).kind == tkAdornment:
|
||||||
inc p.idx # XXX: check?
|
inc p.idx # XXX: check?
|
||||||
if currentTok(p).kind == tkIndent: inc p.idx
|
if currentTok(p).kind == tkIndent: inc p.idx
|
||||||
|
addAnchor(p, rstnodeToRefname(result), reset=true)
|
||||||
|
|
||||||
proc parseBulletList(p: var RstParser): PRstNode =
|
proc parseBulletList(p: var RstParser): PRstNode =
|
||||||
result = nil
|
result = nil
|
||||||
if nextTok(p).kind == tkWhite:
|
if nextTok(p).kind == tkWhite:
|
||||||
var bullet = currentTok(p).symbol
|
var bullet = currentTok(p).symbol
|
||||||
var col = currentTok(p).col
|
var col = currentTok(p).col
|
||||||
result = newRstNode(rnBulletList)
|
result = newRstNodeA(p, rnBulletList)
|
||||||
pushInd(p, p.tok[p.idx + 2].col)
|
pushInd(p, p.tok[p.idx + 2].col)
|
||||||
inc p.idx, 2
|
inc p.idx, 2
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -1497,7 +1569,7 @@ proc parseBulletList(p: var RstParser): PRstNode =
|
||||||
popInd(p)
|
popInd(p)
|
||||||
|
|
||||||
proc parseOptionList(p: var RstParser): PRstNode =
|
proc parseOptionList(p: var RstParser): PRstNode =
|
||||||
result = newRstNode(rnOptionList)
|
result = newRstNodeA(p, rnOptionList)
|
||||||
while true:
|
while true:
|
||||||
if isOptionList(p):
|
if isOptionList(p):
|
||||||
var a = newRstNode(rnOptionGroup)
|
var a = newRstNode(rnOptionGroup)
|
||||||
|
|
@ -1530,7 +1602,7 @@ proc parseDefinitionList(p: var RstParser): PRstNode =
|
||||||
if j >= 1 and p.tok[j].kind == tkIndent and
|
if j >= 1 and p.tok[j].kind == tkIndent and
|
||||||
p.tok[j].ival > currInd(p) and p.tok[j - 1].symbol != "::":
|
p.tok[j].ival > currInd(p) and p.tok[j - 1].symbol != "::":
|
||||||
var col = currentTok(p).col
|
var col = currentTok(p).col
|
||||||
result = newRstNode(rnDefList)
|
result = newRstNodeA(p, rnDefList)
|
||||||
while true:
|
while true:
|
||||||
j = p.idx
|
j = p.idx
|
||||||
var a = newRstNode(rnDefName)
|
var a = newRstNode(rnDefName)
|
||||||
|
|
@ -1568,7 +1640,7 @@ proc parseEnumList(p: var RstParser): PRstNode =
|
||||||
wildToken: array[0..5, int] = [4, 3, 3, 4, 3, 3] # number of tokens
|
wildToken: array[0..5, int] = [4, 3, 3, 4, 3, 3] # number of tokens
|
||||||
wildIndex: array[0..5, int] = [1, 0, 0, 1, 0, 0]
|
wildIndex: array[0..5, int] = [1, 0, 0, 1, 0, 0]
|
||||||
# position of enumeration sequence (number/letter) in enumerator
|
# position of enumeration sequence (number/letter) in enumerator
|
||||||
result = newRstNode(rnEnumList)
|
result = newRstNodeA(p, rnEnumList)
|
||||||
let col = currentTok(p).col
|
let col = currentTok(p).col
|
||||||
var w = 0
|
var w = 0
|
||||||
while w < wildcards.len:
|
while w < wildcards.len:
|
||||||
|
|
@ -1623,6 +1695,7 @@ proc sonKind(father: PRstNode, i: int): RstNodeKind =
|
||||||
if i < father.len: result = father.sons[i].kind
|
if i < father.len: result = father.sons[i].kind
|
||||||
|
|
||||||
proc parseSection(p: var RstParser, result: PRstNode) =
|
proc parseSection(p: var RstParser, result: PRstNode) =
|
||||||
|
## parse top-level RST elements: sections, transitions and body elements.
|
||||||
while true:
|
while true:
|
||||||
var leave = false
|
var leave = false
|
||||||
assert(p.idx >= 0)
|
assert(p.idx >= 0)
|
||||||
|
|
@ -1631,7 +1704,7 @@ proc parseSection(p: var RstParser, result: PRstNode) =
|
||||||
inc p.idx
|
inc p.idx
|
||||||
elif currentTok(p).ival > currInd(p):
|
elif currentTok(p).ival > currInd(p):
|
||||||
pushInd(p, currentTok(p).ival)
|
pushInd(p, currentTok(p).ival)
|
||||||
var a = newRstNode(rnBlockQuote)
|
var a = newRstNodeA(p, rnBlockQuote)
|
||||||
parseSection(p, a)
|
parseSection(p, a)
|
||||||
result.add(a)
|
result.add(a)
|
||||||
popInd(p)
|
popInd(p)
|
||||||
|
|
@ -1667,7 +1740,7 @@ proc parseSection(p: var RstParser, result: PRstNode) =
|
||||||
#InternalError("rst.parseSection()")
|
#InternalError("rst.parseSection()")
|
||||||
discard
|
discard
|
||||||
if a == nil and k != rnDirective:
|
if a == nil and k != rnDirective:
|
||||||
a = newRstNode(rnParagraph)
|
a = newRstNodeA(p, rnParagraph)
|
||||||
parseParagraph(p, a)
|
parseParagraph(p, a)
|
||||||
result.addIfNotNil(a)
|
result.addIfNotNil(a)
|
||||||
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
|
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
|
||||||
|
|
@ -1703,7 +1776,7 @@ proc parseDirective(p: var RstParser, flags: DirFlags): PRstNode =
|
||||||
##
|
##
|
||||||
## Both rnDirArg and rnFieldList children nodes might be nil, so you need to
|
## Both rnDirArg and rnFieldList children nodes might be nil, so you need to
|
||||||
## check them before accessing.
|
## check them before accessing.
|
||||||
result = newRstNode(rnDirective)
|
result = newRstNodeA(p, rnDirective)
|
||||||
var args: PRstNode = nil
|
var args: PRstNode = nil
|
||||||
var options: PRstNode = nil
|
var options: PRstNode = nil
|
||||||
if hasArg in flags:
|
if hasArg in flags:
|
||||||
|
|
@ -1981,7 +2054,10 @@ proc parseDotDot(p: var RstParser): PRstNode =
|
||||||
var a = getReferenceName(p, ":")
|
var a = getReferenceName(p, ":")
|
||||||
if currentTok(p).kind == tkWhite: inc p.idx
|
if currentTok(p).kind == tkWhite: inc p.idx
|
||||||
var b = untilEol(p)
|
var b = untilEol(p)
|
||||||
setRef(p, rstnodeToRefname(a), b)
|
if len(b) == 0 and b.text == "": # set internal anchor
|
||||||
|
addAnchor(p, rstnodeToRefname(a), reset=false)
|
||||||
|
else: # external hyperlink
|
||||||
|
setRef(p, rstnodeToRefname(a), b)
|
||||||
elif match(p, p.idx, " |"):
|
elif match(p, p.idx, " |"):
|
||||||
# substitution definitions:
|
# substitution definitions:
|
||||||
inc p.idx, 2
|
inc p.idx, 2
|
||||||
|
|
@ -2009,6 +2085,7 @@ proc parseDotDot(p: var RstParser): PRstNode =
|
||||||
result = parseComment(p)
|
result = parseComment(p)
|
||||||
|
|
||||||
proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode =
|
proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode =
|
||||||
|
## resolve substitutions and anchor aliases
|
||||||
result = n
|
result = n
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -2022,12 +2099,20 @@ proc resolveSubs(p: var RstParser, n: PRstNode): PRstNode =
|
||||||
if e != "": result = newRstNode(rnLeaf, e)
|
if e != "": result = newRstNode(rnLeaf, e)
|
||||||
else: rstMessage(p, mwUnknownSubstitution, key)
|
else: rstMessage(p, mwUnknownSubstitution, key)
|
||||||
of rnRef:
|
of rnRef:
|
||||||
var y = findRef(p, rstnodeToRefname(n))
|
let refn = rstnodeToRefname(n)
|
||||||
|
var y = findRef(p, refn)
|
||||||
if y != nil:
|
if y != nil:
|
||||||
result = newRstNode(rnHyperlink)
|
result = newRstNode(rnHyperlink)
|
||||||
n.kind = rnInner
|
n.kind = rnInner
|
||||||
result.add(n)
|
result.add(n)
|
||||||
result.add(y)
|
result.add(y)
|
||||||
|
else:
|
||||||
|
let s = findMainAnchor(p, refn)
|
||||||
|
if s != "":
|
||||||
|
result = newRstNode(rnInternalRef)
|
||||||
|
n.kind = rnInner
|
||||||
|
result.add(n)
|
||||||
|
result.add(newRstNode(rnLeaf, s))
|
||||||
of rnLeaf:
|
of rnLeaf:
|
||||||
discard
|
discard
|
||||||
of rnContents:
|
of rnContents:
|
||||||
|
|
@ -2045,5 +2130,6 @@ proc rstParse*(text, filename: string,
|
||||||
p.filename = filename
|
p.filename = filename
|
||||||
p.line = line
|
p.line = line
|
||||||
p.col = column + getTokens(text, roSkipPounds in options, p.tok)
|
p.col = column + getTokens(text, roSkipPounds in options, p.tok)
|
||||||
result = resolveSubs(p, parseDoc(p))
|
let unresolved = parseDoc(p)
|
||||||
|
result = resolveSubs(p, unresolved)
|
||||||
hasToc = p.hasToc
|
hasToc = p.hasToc
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type
|
||||||
rnLabel, # used for footnotes and other things
|
rnLabel, # used for footnotes and other things
|
||||||
rnFootnote, # a footnote
|
rnFootnote, # a footnote
|
||||||
rnCitation, # similar to footnote
|
rnCitation, # similar to footnote
|
||||||
rnStandaloneHyperlink, rnHyperlink, rnRef,
|
rnStandaloneHyperlink, rnHyperlink, rnRef, rnInternalRef,
|
||||||
rnDirective, # a general directive
|
rnDirective, # a general directive
|
||||||
rnDirArg, # a directive argument (for some directives).
|
rnDirArg, # a directive argument (for some directives).
|
||||||
# here are directives that are not rnDirective:
|
# here are directives that are not rnDirective:
|
||||||
|
|
@ -62,6 +62,7 @@ type
|
||||||
rnTripleEmphasis, # "***"
|
rnTripleEmphasis, # "***"
|
||||||
rnInterpretedText, # "`"
|
rnInterpretedText, # "`"
|
||||||
rnInlineLiteral, # "``"
|
rnInlineLiteral, # "``"
|
||||||
|
rnInlineTarget, # "_`target`"
|
||||||
rnSubstitutionReferences, # "|"
|
rnSubstitutionReferences, # "|"
|
||||||
rnSmiley, # some smiley
|
rnSmiley, # some smiley
|
||||||
rnLeaf # a leaf; the node's text field contains the
|
rnLeaf # a leaf; the node's text field contains the
|
||||||
|
|
@ -75,7 +76,9 @@ type
|
||||||
text*: string ## valid for leafs in the AST; and the title of
|
text*: string ## valid for leafs in the AST; and the title of
|
||||||
## the document or the section; and rnEnumList
|
## the document or the section; and rnEnumList
|
||||||
## and rnAdmonition; and rnLineBlockItem
|
## and rnAdmonition; and rnLineBlockItem
|
||||||
level*: int ## valid for some node kinds
|
level*: int ## valid for headlines/overlines only
|
||||||
|
anchor*: string ## anchor, internal link target
|
||||||
|
## (aka HTML id tag, aka Latex label/hypertarget)
|
||||||
sons*: RstNodeSeq ## the node's sons
|
sons*: RstNodeSeq ## the node's sons
|
||||||
|
|
||||||
proc len*(n: PRstNode): int =
|
proc len*(n: PRstNode): int =
|
||||||
|
|
@ -330,8 +333,9 @@ proc renderRstToStr*(node: PRstNode, indent=0): string =
|
||||||
if node == nil:
|
if node == nil:
|
||||||
result.add " ".repeat(indent) & "[nil]\n"
|
result.add " ".repeat(indent) & "[nil]\n"
|
||||||
return
|
return
|
||||||
result.add " ".repeat(indent) & $node.kind & "\t" &
|
result.add " ".repeat(indent) & $node.kind &
|
||||||
(if node.text == "": "" else: "'" & node.text & "'") &
|
(if node.text == "": "" else: "\t'" & node.text & "'") &
|
||||||
(if node.level == 0: "" else: "\tlevel=" & $node.level) & "\n"
|
(if node.level == 0: "" else: "\tlevel=" & $node.level) &
|
||||||
|
(if node.anchor == "": "" else: "\tanchor='" & node.anchor & "'") & "\n"
|
||||||
for son in node.sons:
|
for son in node.sons:
|
||||||
result.add renderRstToStr(son, indent=indent+2)
|
result.add renderRstToStr(son, indent=indent+2)
|
||||||
|
|
|
||||||
|
|
@ -272,13 +272,25 @@ proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string)
|
||||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||||
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
|
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
|
||||||
|
|
||||||
proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
|
template idS(txt: string): string =
|
||||||
|
if txt == "": ""
|
||||||
|
else:
|
||||||
|
case d.target
|
||||||
|
of outHtml:
|
||||||
|
" id=\"" & txt & "\""
|
||||||
|
of outLatex:
|
||||||
|
"\\label{" & txt & "}\\hypertarget{" & txt & "}{}"
|
||||||
|
# we add \label for page number references via \pageref, while
|
||||||
|
# \hypertarget is for clickable links via \hyperlink.
|
||||||
|
|
||||||
|
proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string) =
|
||||||
|
# formats sons of `n` as substitution variable $1 inside strings `html` and
|
||||||
|
# `tex`, internal target (anchor) is provided as substitute $2.
|
||||||
var tmp = ""
|
var tmp = ""
|
||||||
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], tmp)
|
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], tmp)
|
||||||
if d.target != outLatex:
|
case d.target
|
||||||
result.addf(frmtA, [tmp])
|
of outHtml: result.addf(html, [tmp, n.anchor.idS])
|
||||||
else:
|
of outLatex: result.addf(tex, [tmp, n.anchor.idS])
|
||||||
result.addf(frmtB, [tmp])
|
|
||||||
|
|
||||||
# ---------------- index handling --------------------------------------------
|
# ---------------- index handling --------------------------------------------
|
||||||
|
|
||||||
|
|
@ -746,13 +758,13 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
d.tocPart[length].n = n
|
d.tocPart[length].n = n
|
||||||
d.tocPart[length].header = tmp
|
d.tocPart[length].header = tmp
|
||||||
|
|
||||||
dispA(d.target, result, "\n<h$1><a class=\"toc-backref\" " &
|
dispA(d.target, result, "\n<h$1><a class=\"toc-backref\"" &
|
||||||
"id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
|
"$2 href=\"#$5\">$3</a></h$1>", "\\rsth$4{$3}$2\n",
|
||||||
[$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
|
[$n.level, refname.idS, tmp, $chr(n.level - 1 + ord('A')), refname])
|
||||||
else:
|
else:
|
||||||
dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
|
dispA(d.target, result, "\n<h$1$2>$3</h$1>",
|
||||||
"\\rsth$4{$3}\\label{$2}\n", [
|
"\\rsth$4{$3}$2\n", [
|
||||||
$n.level, refname, tmp,
|
$n.level, refname.idS, tmp,
|
||||||
$chr(n.level - 1 + ord('A'))])
|
$chr(n.level - 1 + ord('A'))])
|
||||||
|
|
||||||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||||
|
|
@ -781,9 +793,9 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
var tmp = ""
|
var tmp = ""
|
||||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||||
d.currentSection = tmp
|
d.currentSection = tmp
|
||||||
dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
|
dispA(d.target, result, "<h$1$2><center>$3</center></h$1>",
|
||||||
"\\rstov$4{$3}\\label{$2}\n", [$n.level,
|
"\\rstov$4{$3}$2\n", [$n.level,
|
||||||
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
|
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A'))])
|
||||||
|
|
||||||
|
|
||||||
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
||||||
|
|
@ -841,12 +853,12 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||||
if arg.endsWith(".mp4") or arg.endsWith(".ogg") or
|
if arg.endsWith(".mp4") or arg.endsWith(".ogg") or
|
||||||
arg.endsWith(".webm"):
|
arg.endsWith(".webm"):
|
||||||
htmlOut = """
|
htmlOut = """
|
||||||
<video src="$1"$2 autoPlay='true' loop='true' muted='true'>
|
<video$3 src="$1"$2 autoPlay='true' loop='true' muted='true'>
|
||||||
Sorry, your browser doesn't support embedded videos
|
Sorry, your browser doesn't support embedded videos
|
||||||
</video>
|
</video>
|
||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
htmlOut = "<img src=\"$1\"$2/>"
|
htmlOut = "<img$3 src=\"$1\"$2/>"
|
||||||
|
|
||||||
# support for `:target:` links for images:
|
# support for `:target:` links for images:
|
||||||
var target = esc(d.target, getFieldValue(n, "target").strip())
|
var target = esc(d.target, getFieldValue(n, "target").strip())
|
||||||
|
|
@ -859,8 +871,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||||
"\\href{$2}{$1}", [htmlOut, target])
|
"\\href{$2}{$1}", [htmlOut, target])
|
||||||
htmlOut = htmlOutWithLink
|
htmlOut = htmlOutWithLink
|
||||||
|
|
||||||
dispA(d.target, result, htmlOut, "\\includegraphics$2{$1}",
|
dispA(d.target, result, htmlOut, "$3\\includegraphics$2{$1}",
|
||||||
[esc(d.target, arg), options])
|
[esc(d.target, arg), options, n.anchor.idS])
|
||||||
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
|
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
|
||||||
|
|
||||||
proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
||||||
|
|
@ -925,7 +937,8 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams =
|
||||||
if result.langStr != "":
|
if result.langStr != "":
|
||||||
result.lang = getSourceLanguage(result.langStr)
|
result.lang = getSourceLanguage(result.langStr)
|
||||||
|
|
||||||
proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string):
|
proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string,
|
||||||
|
idStr: string):
|
||||||
tuple[beginTable, endTable: string] =
|
tuple[beginTable, endTable: string] =
|
||||||
## Returns the necessary tags to start/end a code block in HTML.
|
## Returns the necessary tags to start/end a code block in HTML.
|
||||||
##
|
##
|
||||||
|
|
@ -937,21 +950,22 @@ proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string):
|
||||||
let id = $d.listingCounter
|
let id = $d.listingCounter
|
||||||
if not params.numberLines:
|
if not params.numberLines:
|
||||||
result = (d.config.getOrDefault"doc.listing_start" %
|
result = (d.config.getOrDefault"doc.listing_start" %
|
||||||
[id, sourceLanguageToStr[params.lang]],
|
[id, sourceLanguageToStr[params.lang], idStr],
|
||||||
d.config.getOrDefault"doc.listing_end" % id)
|
d.config.getOrDefault"doc.listing_end" % id)
|
||||||
return
|
return
|
||||||
|
|
||||||
var codeLines = code.strip.countLines
|
var codeLines = code.strip.countLines
|
||||||
assert codeLines > 0
|
assert codeLines > 0
|
||||||
result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre class="line-nums">"""
|
result.beginTable = """<table$1 class="line-nums-table">""" % [idStr] &
|
||||||
|
"""<tbody><tr><td class="blob-line-nums"><pre class="line-nums">"""
|
||||||
var line = params.startLine
|
var line = params.startLine
|
||||||
while codeLines > 0:
|
while codeLines > 0:
|
||||||
result.beginTable.add($line & "\n")
|
result.beginTable.add($line & "\n")
|
||||||
line.inc
|
line.inc
|
||||||
codeLines.dec
|
codeLines.dec
|
||||||
result.beginTable.add("</pre></td><td>" & (
|
result.beginTable.add("</pre$3></td><td>" & (
|
||||||
d.config.getOrDefault"doc.listing_start" %
|
d.config.getOrDefault"doc.listing_start" %
|
||||||
[id, sourceLanguageToStr[params.lang]]))
|
[id, sourceLanguageToStr[params.lang], idStr]))
|
||||||
result.endTable = (d.config.getOrDefault"doc.listing_end" % id) &
|
result.endTable = (d.config.getOrDefault"doc.listing_end" % id) &
|
||||||
"</td></tr></tbody></table>" & (
|
"</td></tr></tbody></table>" & (
|
||||||
d.config.getOrDefault"doc.listing_button" % id)
|
d.config.getOrDefault"doc.listing_button" % id)
|
||||||
|
|
@ -975,9 +989,10 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||||
if params.testCmd.len > 0 and d.onTestSnippet != nil:
|
if params.testCmd.len > 0 and d.onTestSnippet != nil:
|
||||||
d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text)
|
d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text)
|
||||||
|
|
||||||
let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text)
|
let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text,
|
||||||
|
n.anchor.idS)
|
||||||
dispA(d.target, result, blockStart, "\\begin{rstpre}\n", [])
|
dispA(d.target, result, blockStart,
|
||||||
|
"\\begin{rstpre}\n" & n.anchor.idS & "\n", [])
|
||||||
if params.lang == langNone:
|
if params.lang == langNone:
|
||||||
if len(params.langStr) > 0:
|
if len(params.langStr) > 0:
|
||||||
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr)
|
d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr)
|
||||||
|
|
@ -1075,8 +1090,8 @@ proc renderEnumList(d: PDoc, n: PRstNode, result: var string) =
|
||||||
if n.text[i1] != first:
|
if n.text[i1] != first:
|
||||||
specStart = " start=\"$1\"" % [ $(ord(n.text[i1]) - ord(first) + 1) ]
|
specStart = " start=\"$1\"" % [ $(ord(n.text[i1]) - ord(first) + 1) ]
|
||||||
specifier = labelDef & specStart
|
specifier = labelDef & specStart
|
||||||
renderAux(d, n, "<ol " & specifier & ">$1</ol>\n",
|
renderAux(d, n, "<ol$2 " & specifier & ">$1</ol>\n",
|
||||||
"\\begin{enumerate}" & specifier & "$1\\end{enumerate}\n",
|
"\\begin{enumerate}" & specifier & "$2$1\\end{enumerate}\n",
|
||||||
result)
|
result)
|
||||||
|
|
||||||
proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) =
|
proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) =
|
||||||
|
|
@ -1095,9 +1110,9 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) =
|
||||||
let txt = n.text.capitalizeAscii()
|
let txt = n.text.capitalizeAscii()
|
||||||
let htmlHead = "<div class=\"admonition " & htmlCls & "\">"
|
let htmlHead = "<div class=\"admonition " & htmlCls & "\">"
|
||||||
renderAux(d, n,
|
renderAux(d, n,
|
||||||
htmlHead & "<span class=\"" & htmlCls & "-text\"><b>" & txt &
|
htmlHead & "<span$2 class=\"" & htmlCls & "-text\"><b>" & txt &
|
||||||
":</b></span>\n" & "$1</div>\n",
|
":</b></span>\n" & "$1</div>\n",
|
||||||
"\n\n\\begin{mdframed}[linecolor=" & texColor & "]\n" &
|
"\n\n\\begin{mdframed}[linecolor=" & texColor & "]$2\n" &
|
||||||
"{" & texSz & "\\color{" & texColor & "}{\\textbf{" & txt & ":}}} " &
|
"{" & texSz & "\\color{" & texColor & "}{\\textbf{" & txt & ":}}} " &
|
||||||
"$1\n\\end{mdframed}\n",
|
"$1\n\\end{mdframed}\n",
|
||||||
result)
|
result)
|
||||||
|
|
@ -1108,33 +1123,33 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
of rnInner: renderAux(d, n, result)
|
of rnInner: renderAux(d, n, result)
|
||||||
of rnHeadline: renderHeadline(d, n, result)
|
of rnHeadline: renderHeadline(d, n, result)
|
||||||
of rnOverline: renderOverline(d, n, result)
|
of rnOverline: renderOverline(d, n, result)
|
||||||
of rnTransition: renderAux(d, n, "<hr />\n", "\\hrule\n", result)
|
of rnTransition: renderAux(d, n, "<hr$2 />\n", "\\hrule$2\n", result)
|
||||||
of rnParagraph: renderAux(d, n, "<p>$1</p>\n", "$1\n\n", result)
|
of rnParagraph: renderAux(d, n, "<p$2>$1</p>\n", "$2\n$1\n\n", result)
|
||||||
of rnBulletList:
|
of rnBulletList:
|
||||||
renderAux(d, n, "<ul class=\"simple\">$1</ul>\n",
|
renderAux(d, n, "<ul$2 class=\"simple\">$1</ul>\n",
|
||||||
"\\begin{itemize}$1\\end{itemize}\n", result)
|
"\\begin{itemize}\n$2\n$1\\end{itemize}\n", result)
|
||||||
of rnBulletItem, rnEnumItem:
|
of rnBulletItem, rnEnumItem:
|
||||||
renderAux(d, n, "<li>$1</li>\n", "\\item $1\n", result)
|
renderAux(d, n, "<li$2>$1</li>\n", "\\item $2$1\n", result)
|
||||||
of rnEnumList: renderEnumList(d, n, result)
|
of rnEnumList: renderEnumList(d, n, result)
|
||||||
of rnDefList:
|
of rnDefList:
|
||||||
renderAux(d, n, "<dl class=\"docutils\">$1</dl>\n",
|
renderAux(d, n, "<dl$2 class=\"docutils\">$1</dl>\n",
|
||||||
"\\begin{description}$1\\end{description}\n", result)
|
"\\begin{description}\n$2\n$1\\end{description}\n", result)
|
||||||
of rnDefItem: renderAux(d, n, result)
|
of rnDefItem: renderAux(d, n, result)
|
||||||
of rnDefName: renderAux(d, n, "<dt>$1</dt>\n", "\\item[$1] ", result)
|
of rnDefName: renderAux(d, n, "<dt$2>$1</dt>\n", "$2\\item[$1] ", result)
|
||||||
of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
|
of rnDefBody: renderAux(d, n, "<dd$2>$1</dd>\n", "$2\n$1\n", result)
|
||||||
of rnFieldList:
|
of rnFieldList:
|
||||||
var tmp = ""
|
var tmp = ""
|
||||||
for i in countup(0, len(n) - 1):
|
for i in countup(0, len(n) - 1):
|
||||||
renderRstToOut(d, n.sons[i], tmp)
|
renderRstToOut(d, n.sons[i], tmp)
|
||||||
if tmp.len != 0:
|
if tmp.len != 0:
|
||||||
dispA(d.target, result,
|
dispA(d.target, result,
|
||||||
"<table class=\"docinfo\" frame=\"void\" rules=\"none\">" &
|
"<table$2 class=\"docinfo\" frame=\"void\" rules=\"none\">" &
|
||||||
"<col class=\"docinfo-name\" />" &
|
"<col class=\"docinfo-name\" />" &
|
||||||
"<col class=\"docinfo-content\" />" &
|
"<col class=\"docinfo-content\" />" &
|
||||||
"<tbody valign=\"top\">$1" &
|
"<tbody valign=\"top\">$1" &
|
||||||
"</tbody></table>",
|
"</tbody></table>",
|
||||||
"\\begin{description}$1\\end{description}\n",
|
"\\begin{description}\n$2\n$1\\end{description}\n",
|
||||||
[tmp])
|
[tmp, n.anchor.idS])
|
||||||
of rnField: renderField(d, n, result)
|
of rnField: renderField(d, n, result)
|
||||||
of rnFieldName:
|
of rnFieldName:
|
||||||
renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
|
renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
|
||||||
|
|
@ -1144,8 +1159,8 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
of rnIndex:
|
of rnIndex:
|
||||||
renderRstToOut(d, n.sons[2], result)
|
renderRstToOut(d, n.sons[2], result)
|
||||||
of rnOptionList:
|
of rnOptionList:
|
||||||
renderAux(d, n, "<table frame=\"void\">$1</table>",
|
renderAux(d, n, "<table$2 frame=\"void\">$1</table>",
|
||||||
"\\begin{description}\n$1\\end{description}\n", result)
|
"\\begin{description}\n$2\n$1\\end{description}\n", result)
|
||||||
of rnOptionListItem:
|
of rnOptionListItem:
|
||||||
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
||||||
of rnOptionGroup:
|
of rnOptionGroup:
|
||||||
|
|
@ -1155,16 +1170,17 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
of rnOption, rnOptionString, rnOptionArgument:
|
of rnOption, rnOptionString, rnOptionArgument:
|
||||||
doAssert false, "renderRstToOut"
|
doAssert false, "renderRstToOut"
|
||||||
of rnLiteralBlock:
|
of rnLiteralBlock:
|
||||||
renderAux(d, n, "<pre>$1</pre>\n",
|
renderAux(d, n, "<pre$2>$1</pre>\n",
|
||||||
"\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
|
"\\begin{rstpre}\n$2\n$1\n\\end{rstpre}\n", result)
|
||||||
of rnQuotedLiteralBlock:
|
of rnQuotedLiteralBlock:
|
||||||
doAssert false, "renderRstToOut"
|
doAssert false, "renderRstToOut"
|
||||||
of rnLineBlock:
|
of rnLineBlock:
|
||||||
if n.sons.len == 1 and n.sons[0].text == "\n":
|
if n.sons.len == 1 and n.sons[0].text == "\n":
|
||||||
# whole line block is one empty line, no need to add extra spacing
|
# whole line block is one empty line, no need to add extra spacing
|
||||||
renderAux(d, n, "<p>$1</p> ", "\n\n$1", result)
|
renderAux(d, n, "<p$2>$1</p> ", "\n\n$2\n$1", result)
|
||||||
else: # add extra spacing around the line block for Latex
|
else: # add extra spacing around the line block for Latex
|
||||||
renderAux(d, n, "<p>$1</p>", "\n\\vspace{0.5em}\n$1\\vspace{0.5em}\n", result)
|
renderAux(d, n, "<p$2>$1</p>",
|
||||||
|
"\n\\vspace{0.5em}$2\n$1\\vspace{0.5em}\n", result)
|
||||||
of rnLineBlockItem:
|
of rnLineBlockItem:
|
||||||
if n.text.len == 0: # normal case - no additional indentation
|
if n.text.len == 0: # normal case - no additional indentation
|
||||||
renderAux(d, n, "$1<br/>", "\\noindent $1\n\n", result)
|
renderAux(d, n, "$1<br/>", "\\noindent $1\n\n", result)
|
||||||
|
|
@ -1176,13 +1192,13 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
"<span style=\"margin-left: " & indent & "\">$1</span><br/>",
|
"<span style=\"margin-left: " & indent & "\">$1</span><br/>",
|
||||||
"\\noindent\\hspace{" & indent & "}$1\n\n", result)
|
"\\noindent\\hspace{" & indent & "}$1\n\n", result)
|
||||||
of rnBlockQuote:
|
of rnBlockQuote:
|
||||||
renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
|
renderAux(d, n, "<blockquote$2><p>$1</p></blockquote>\n",
|
||||||
"\\begin{quote}$1\\end{quote}\n", result)
|
"\\begin{quote}\n$2\n$1\\end{quote}\n", result)
|
||||||
of rnAdmonition: renderAdmonition(d, n, result)
|
of rnAdmonition: renderAdmonition(d, n, result)
|
||||||
of rnTable, rnGridTable, rnMarkdownTable:
|
of rnTable, rnGridTable, rnMarkdownTable:
|
||||||
renderAux(d, n,
|
renderAux(d, n,
|
||||||
"<table border=\"1\" class=\"docutils\">$1</table>",
|
"<table$2 border=\"1\" class=\"docutils\">$1</table>",
|
||||||
"\\begin{table}\\begin{rsttab}{" &
|
"\\begin{table}\n$2\n\\begin{rsttab}{" &
|
||||||
texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
|
texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
|
||||||
of rnTableRow:
|
of rnTableRow:
|
||||||
if len(n) >= 1:
|
if len(n) >= 1:
|
||||||
|
|
@ -1217,6 +1233,12 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
renderAux(d, n,
|
renderAux(d, n,
|
||||||
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
||||||
"\\href{$1}{$1}", result)
|
"\\href{$1}{$1}", result)
|
||||||
|
of rnInternalRef:
|
||||||
|
var tmp = ""
|
||||||
|
renderAux(d, n.sons[0], tmp)
|
||||||
|
dispA(d.target, result,
|
||||||
|
"<a class=\"reference internal\" href=\"#$2\">$1</a>",
|
||||||
|
"\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [tmp, n.sons[1].text])
|
||||||
of rnHyperlink:
|
of rnHyperlink:
|
||||||
var tmp0 = ""
|
var tmp0 = ""
|
||||||
var tmp1 = ""
|
var tmp1 = ""
|
||||||
|
|
@ -1261,6 +1283,13 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||||
renderAux(d, n,
|
renderAux(d, n,
|
||||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||||
"\\texttt{$1}", result)
|
"\\texttt{$1}", result)
|
||||||
|
of rnInlineTarget:
|
||||||
|
var tmp = ""
|
||||||
|
renderAux(d, n, tmp)
|
||||||
|
dispA(d.target, result,
|
||||||
|
"<span class=\"target\" id=\"$2\">$1</span>",
|
||||||
|
"\\label{$2}\\hypertarget{$2}{$1}",
|
||||||
|
[tmp, rstnodeToRefname(n)])
|
||||||
of rnSmiley: renderSmiley(d, n, result)
|
of rnSmiley: renderSmiley(d, n, result)
|
||||||
of rnLeaf: result.add(esc(d.target, n.text))
|
of rnLeaf: result.add(esc(d.target, n.text))
|
||||||
of rnContents: d.hasToc = true
|
of rnContents: d.hasToc = true
|
||||||
|
|
@ -1396,7 +1425,7 @@ $moduledesc
|
||||||
$content
|
$content
|
||||||
</div>
|
</div>
|
||||||
""")
|
""")
|
||||||
setConfigVar("doc.listing_start", "<pre class = \"listing\">")
|
setConfigVar("doc.listing_start", "<pre$3 class = \"listing\">")
|
||||||
setConfigVar("doc.listing_end", "</pre>")
|
setConfigVar("doc.listing_end", "</pre>")
|
||||||
setConfigVar("doc.listing_button", "</pre>")
|
setConfigVar("doc.listing_button", "</pre>")
|
||||||
setConfigVar("doc.body_no_toc", "$moduledesc $content")
|
setConfigVar("doc.body_no_toc", "$moduledesc $content")
|
||||||
|
|
|
||||||
|
|
@ -625,6 +625,164 @@ Test1
|
||||||
doAssert "endOfNote</div>" in output3
|
doAssert "endOfNote</div>" in output3
|
||||||
doAssert "class=\"admonition admonition-info\"" in output3
|
doAssert "class=\"admonition admonition-info\"" in output3
|
||||||
|
|
||||||
|
test "RST internal links":
|
||||||
|
let input1 = dedent """
|
||||||
|
Start.
|
||||||
|
|
||||||
|
.. _target000:
|
||||||
|
|
||||||
|
Paragraph.
|
||||||
|
|
||||||
|
.. _target001:
|
||||||
|
|
||||||
|
* bullet list
|
||||||
|
* Y
|
||||||
|
|
||||||
|
.. _target002:
|
||||||
|
|
||||||
|
1. enumeration list
|
||||||
|
2. Y
|
||||||
|
|
||||||
|
.. _target003:
|
||||||
|
|
||||||
|
term 1
|
||||||
|
Definition list 1.
|
||||||
|
|
||||||
|
.. _target004:
|
||||||
|
|
||||||
|
| line block
|
||||||
|
|
||||||
|
.. _target005:
|
||||||
|
|
||||||
|
:a: field list value
|
||||||
|
|
||||||
|
.. _target006:
|
||||||
|
|
||||||
|
-a option description
|
||||||
|
|
||||||
|
.. _target007:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Literal block
|
||||||
|
|
||||||
|
.. _target008:
|
||||||
|
|
||||||
|
Doctest blocks are not implemented.
|
||||||
|
|
||||||
|
.. _target009:
|
||||||
|
|
||||||
|
block quote
|
||||||
|
|
||||||
|
.. _target010:
|
||||||
|
|
||||||
|
===== ===== =======
|
||||||
|
A B A and B
|
||||||
|
===== ===== =======
|
||||||
|
False False False
|
||||||
|
===== ===== =======
|
||||||
|
|
||||||
|
.. _target100:
|
||||||
|
|
||||||
|
.. CAUTION:: admonition
|
||||||
|
|
||||||
|
.. _target101:
|
||||||
|
|
||||||
|
.. code:: nim
|
||||||
|
|
||||||
|
const pi = 3.14
|
||||||
|
|
||||||
|
.. _target102:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
const pi = 3.14
|
||||||
|
|
||||||
|
Paragraph2.
|
||||||
|
|
||||||
|
.. _target202:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
That was a transition.
|
||||||
|
"""
|
||||||
|
let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
|
||||||
|
doAssert "<p id=\"target000\"" in output1
|
||||||
|
doAssert "<ul id=\"target001\"" in output1
|
||||||
|
doAssert "<ol id=\"target002\"" in output1
|
||||||
|
doAssert "<dl id=\"target003\"" in output1
|
||||||
|
doAssert "<p id=\"target004\"" in output1
|
||||||
|
doAssert "<table id=\"target005\"" in output1 # field list
|
||||||
|
doAssert "<table id=\"target006\"" in output1 # option list
|
||||||
|
doAssert "<pre id=\"target007\"" in output1
|
||||||
|
doAssert "<blockquote id=\"target009\"" in output1
|
||||||
|
doAssert "<table id=\"target010\"" in output1 # just table
|
||||||
|
doAssert "<span id=\"target100\"" in output1
|
||||||
|
doAssert "<pre id=\"target101\"" in output1 # code
|
||||||
|
doAssert "<pre id=\"target102\"" in output1 # code-block
|
||||||
|
doAssert "<hr id=\"target202\"" in output1
|
||||||
|
|
||||||
|
test "RST internal links for sections":
|
||||||
|
let input1 = dedent """
|
||||||
|
.. _target101:
|
||||||
|
.. _target102:
|
||||||
|
|
||||||
|
Section xyz
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Ref. target101_
|
||||||
|
"""
|
||||||
|
let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
|
||||||
|
# "target101" should be erased and changed to "section-xyz":
|
||||||
|
doAssert "href=\"#target101\"" notin output1
|
||||||
|
doAssert "id=\"target101\"" notin output1
|
||||||
|
doAssert "href=\"#target102\"" notin output1
|
||||||
|
doAssert "id=\"target102\"" notin output1
|
||||||
|
doAssert "id=\"section-xyz\"" in output1
|
||||||
|
doAssert "href=\"#section-xyz\"" in output1
|
||||||
|
|
||||||
|
let input2 = dedent """
|
||||||
|
.. _target300:
|
||||||
|
|
||||||
|
Section xyz
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. _target301:
|
||||||
|
|
||||||
|
SubsectionA
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Ref. target300_ and target301_.
|
||||||
|
"""
|
||||||
|
let output2 = rstToHtml(input2, {roSupportMarkdown}, defaultConfig())
|
||||||
|
# "target101" should be erased and changed to "section-xyz":
|
||||||
|
doAssert "href=\"#target300\"" notin output2
|
||||||
|
doAssert "id=\"target300\"" notin output2
|
||||||
|
doAssert "href=\"#target301\"" notin output2
|
||||||
|
doAssert "id=\"target301\"" notin output2
|
||||||
|
doAssert "<h1 id=\"section-xyz\"" in output2
|
||||||
|
doAssert "<h2 id=\"subsectiona\"" in output2
|
||||||
|
# links should preserve their original names but point to section labels:
|
||||||
|
doAssert "href=\"#section-xyz\">target300" in output2
|
||||||
|
doAssert "href=\"#subsectiona\">target301" in output2
|
||||||
|
|
||||||
|
let output2l = rstToLatex(input2, {})
|
||||||
|
doAssert "\\label{section-xyz}\\hypertarget{section-xyz}{}" in output2l
|
||||||
|
doAssert "\\hyperlink{section-xyz}{target300}" in output2l
|
||||||
|
doAssert "\\hyperlink{subsectiona}{target301}" in output2l
|
||||||
|
|
||||||
|
test "RST internal links (inline)":
|
||||||
|
let input1 = dedent """
|
||||||
|
Paragraph with _`some definition`.
|
||||||
|
|
||||||
|
Ref. `some definition`_.
|
||||||
|
"""
|
||||||
|
let output1 = rstToHtml(input1, {roSupportMarkdown}, defaultConfig())
|
||||||
|
doAssert "<span class=\"target\" " &
|
||||||
|
"id=\"some-definition\">some definition</span>" in output1
|
||||||
|
doAssert "Ref. <a class=\"reference internal\" " &
|
||||||
|
"href=\"#some-definition\">some definition</a>" in output1
|
||||||
|
|
||||||
suite "RST/Code highlight":
|
suite "RST/Code highlight":
|
||||||
test "Basic Python code highlight":
|
test "Basic Python code highlight":
|
||||||
let pythonCode = """
|
let pythonCode = """
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue