mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-07 13:33:22 +00:00
Implement Pandoc Markdown concise link extension (#20304)
* Implement Pandoc Markdown concise link extension This implements https://github.com/nim-lang/Nim/issues/20127. Besides reference to headings we also support doing references to Nim symbols inside Nim modules. Markdown: ``` Some heading ------------ Ref. [Some heading]. ``` Nim: ``` proc someFunction*() ... ... ## Ref. [someFunction] ``` This is substitution for RST syntax like `` `target`_ ``. All 3 syntax variants of extension from Pandoc Markdown are supported: `[target]`, `[target][]`, `[description][target]`. This PR also fixes clashes in existing files, particularly conflicts with RST footnote feature, which does not work with this PR (but there is a plan to adopt a popular [Markdown footnote extension](https://pandoc.org/MANUAL.html#footnotes) to make footnotes work). Also the PR fixes a bug that Markdown links did not work when `[...]` section had a line break. The implementation is straightforward since link resolution did not change w.r.t. RST implementation, it's almost only about new syntax addition. The only essential difference is a possibility to add a custom link description: form `[description][target]` which does not have an RST equivalent. * fix nim 1.0 gotcha
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
Command:
|
||||
//compile, c compile project with default code generator (C)
|
||||
//r compile to $nimcache/projname, run with [arguments]
|
||||
//r compile to $nimcache/projname, run with `arguments`
|
||||
using backend specified by `--backend` (default: c)
|
||||
//doc generate the documentation for inputfile for
|
||||
backend specified by `--backend` (default: c)
|
||||
|
||||
@@ -336,7 +336,7 @@ To avoid accidental highlighting follow this rule in ``*.nim`` files:
|
||||
|
||||
.. Note:: ``*.rst`` files have ``:literal:`` as their default role.
|
||||
So for them the rule above is only applicable if the ``:nim:`` role
|
||||
is set up manually as the default [*]_::
|
||||
is set up manually as the default \[*]::
|
||||
|
||||
.. role:: nim(code)
|
||||
:language: nim
|
||||
@@ -345,7 +345,7 @@ To avoid accidental highlighting follow this rule in ``*.nim`` files:
|
||||
The first 2 lines are for other RST implementations,
|
||||
including Github one.
|
||||
|
||||
.. [*] this is fulfilled when ``doc/rstcommon.rst`` is included.
|
||||
\[*] this is fulfilled when ``doc/rstcommon.rst`` is included.
|
||||
|
||||
Best practices
|
||||
==============
|
||||
@@ -431,7 +431,7 @@ including prepending location info, writing to log files, etc.).
|
||||
```
|
||||
|
||||
.. _use_Option:
|
||||
[Ongoing debate] Consider using Option instead of return bool + var argument,
|
||||
(Ongoing debate) Consider using Option instead of return bool + var argument,
|
||||
unless stack allocation is needed (e.g. for efficiency).
|
||||
|
||||
```nim
|
||||
|
||||
@@ -245,9 +245,9 @@ underscore `_` to a *link text*.
|
||||
Link text is either one word or a group of words enclosed by backticks `\``
|
||||
(for a one word case backticks are usually omitted).
|
||||
Link text will be displayed *as is* while *link target* will be set to
|
||||
the anchor [*]_ of Nim symbol that corresponds to link text.
|
||||
the anchor \[*] of Nim symbol that corresponds to link text.
|
||||
|
||||
.. [*] anchors' format is described in `HTML anchor generation`_ section below.
|
||||
[*] anchors' format is described in `HTML anchor generation`_ section below.
|
||||
|
||||
If you have a constant:
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ symbol for which idetools returns valid output.
|
||||
skConst
|
||||
-------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + const name.
|
||||
| **Third column**: module + \[n scope nesting] + const name.
|
||||
| **Fourth column**: the type of the const value.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -254,7 +254,7 @@ skConst
|
||||
skEnumField
|
||||
-----------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + enum type + enum field name.
|
||||
| **Third column**: module + \[n scope nesting] + enum type + enum field name.
|
||||
| **Fourth column**: enum type grouping other enum fields.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -269,7 +269,7 @@ skEnumField
|
||||
skForVar
|
||||
--------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + var name.
|
||||
| **Third column**: module + \[n scope nesting] + var name.
|
||||
| **Fourth column**: type of the var.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -291,7 +291,7 @@ defined, since at that point in the file the parser hasn't processed
|
||||
the full line yet. The signature will be returned complete in
|
||||
posterior instances of the iterator.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + iterator name.
|
||||
| **Third column**: module + \[n scope nesting] + iterator name.
|
||||
| **Fourth column**: signature of the iterator including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
@@ -308,7 +308,7 @@ posterior instances of the iterator.
|
||||
skLabel
|
||||
-------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + name.
|
||||
| **Third column**: module + \[n scope nesting] + name.
|
||||
| **Fourth column**: always the empty string.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -325,7 +325,7 @@ skLabel
|
||||
skLet
|
||||
-----
|
||||
|
||||
| **Third column**: module + [n scope nesting] + let name.
|
||||
| **Third column**: module + \[n scope nesting] + let name.
|
||||
| **Fourth column**: the type of the let variable.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -346,7 +346,7 @@ defined, since at that point in the file the parser hasn't processed
|
||||
the full line yet. The signature will be returned complete in
|
||||
posterior instances of the macro.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + macro name.
|
||||
| **Third column**: module + \[n scope nesting] + macro name.
|
||||
| **Fourth column**: signature of the macro including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
@@ -384,7 +384,7 @@ Note that at the moment the word `proc` is returned for the
|
||||
signature of the found method instead of the expected `method`.
|
||||
This may change in the future.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + method name.
|
||||
| **Third column**: module + \[n scope nesting] + method name.
|
||||
| **Fourth column**: signature of the method including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
@@ -402,7 +402,7 @@ This may change in the future.
|
||||
skParam
|
||||
-------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + param name.
|
||||
| **Third column**: module + \[n scope nesting] + param name.
|
||||
| **Fourth column**: the type of the parameter.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -427,7 +427,7 @@ While at the language level a proc is differentiated from others
|
||||
by the parameters and return value, the signature of the proc
|
||||
returned by idetools returns also the pragmas for the proc.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + proc name.
|
||||
| **Third column**: module + \[n scope nesting] + proc name.
|
||||
| **Fourth column**: signature of the proc including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
@@ -446,7 +446,7 @@ returned by idetools returns also the pragmas for the proc.
|
||||
skResult
|
||||
--------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + result.
|
||||
| **Third column**: module + \[n scope nesting] + result.
|
||||
| **Fourth column**: the type of the result.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -467,7 +467,7 @@ defined, since at that point in the file the parser hasn't processed
|
||||
the full line yet. The signature will be returned complete in
|
||||
posterior instances of the template.
|
||||
|
||||
| **Third column**: module + [n scope nesting] + template name.
|
||||
| **Third column**: module + \[n scope nesting] + template name.
|
||||
| **Fourth column**: signature of the template including return type.
|
||||
| **Docstring**: docstring if available.
|
||||
|
||||
@@ -496,7 +496,7 @@ posterior instances of the template.
|
||||
skType
|
||||
------
|
||||
|
||||
| **Third column**: module + [n scope nesting] + type name.
|
||||
| **Third column**: module + \[n scope nesting] + type name.
|
||||
| **Fourth column**: the type.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
@@ -512,7 +512,7 @@ skType
|
||||
skVar
|
||||
-----
|
||||
|
||||
| **Third column**: module + [n scope nesting] + var name.
|
||||
| **Third column**: module + \[n scope nesting] + var name.
|
||||
| **Fourth column**: the type of the var.
|
||||
| **Docstring**: always the empty string.
|
||||
|
||||
|
||||
@@ -328,7 +328,7 @@ Coding Guidelines
|
||||
* Max line length is 100 characters.
|
||||
* Provide spaces around binary operators if that enhances readability.
|
||||
* Use a space after a colon, but not before it.
|
||||
* [deprecated] Start types with a capital `T`, unless they are
|
||||
* (deprecated) Start types with a capital `T`, unless they are
|
||||
pointers/references which start with `P`.
|
||||
* Prefer `import package`:nim: over `from package import symbol`:nim:.
|
||||
|
||||
|
||||
@@ -2862,11 +2862,11 @@ ref or pointer type nil
|
||||
procedural type nil
|
||||
sequence `@[]`
|
||||
string `""`
|
||||
tuple[x: A, y: B, ...] (default(A), default(B), ...)
|
||||
`tuple[x: A, y: B, ...]` (default(A), default(B), ...)
|
||||
(analogous for objects)
|
||||
array[0..., T] [default(T), ...]
|
||||
range[T] default(T); this may be out of the valid range
|
||||
T = enum cast[T]\(0); this may be an invalid value
|
||||
`array[0..., T]` `[default(T), ...]`
|
||||
`range[T]` default(T); this may be out of the valid range
|
||||
T = enum `cast[T](0)`; this may be an invalid value
|
||||
============================ ==============================================
|
||||
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ template `^^`(n: NimNode, i: untyped): untyped =
|
||||
|
||||
proc `[]`*[T, U: Ordinal](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
|
||||
## Slice operation for NimNode.
|
||||
## Returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
|
||||
## Returns a seq of child of `n` who inclusive range `[n[x.a], n[x.b]]`.
|
||||
let xa = n ^^ x.a
|
||||
let L = (n ^^ x.b) - xa + 1
|
||||
result = newSeq[NimNode](L)
|
||||
|
||||
@@ -180,7 +180,7 @@ iterator fastRows*(db: DbConn, query: SqlQuery,
|
||||
## if you require **ALL** the rows.
|
||||
##
|
||||
## Breaking the fastRows() iterator during a loop will cause the next
|
||||
## database query to raise an [EDb] exception `Commands out of sync`.
|
||||
## database query to raise an `EDb` exception `Commands out of sync`.
|
||||
rawExec(db, query, args)
|
||||
var sqlres = mysql.useResult(PMySQL db)
|
||||
if sqlres != nil:
|
||||
@@ -203,7 +203,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect].} =
|
||||
## Same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within the iterator body.
|
||||
## on demand using `[]`. Returned handle is valid only within the iterator body.
|
||||
rawExec(db, query, args)
|
||||
var sqlres = mysql.useResult(PMySQL db)
|
||||
if sqlres != nil:
|
||||
@@ -283,7 +283,7 @@ proc setColumnInfo(columns: var DbColumns; res: PRES; L: int) =
|
||||
iterator instantRows*(db: DbConn; columns: var DbColumns; query: SqlQuery;
|
||||
args: varargs[string, `$`]): InstantRow =
|
||||
## Same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within the iterator body.
|
||||
## on demand using `[]`. Returned handle is valid only within the iterator body.
|
||||
rawExec(db, query, args)
|
||||
var sqlres = mysql.useResult(PMySQL db)
|
||||
if sqlres != nil:
|
||||
|
||||
@@ -168,7 +168,7 @@ proc dbError*(db: var DbConn) {.
|
||||
raise e
|
||||
|
||||
proc sqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} =
|
||||
## Wrapper that raises [EDb] if `resVal` is neither SQL_SUCCESS or SQL_NO_DATA
|
||||
## Wrapper that raises `EDb` if `resVal` is neither SQL_SUCCESS or SQL_NO_DATA
|
||||
if resVal notIn [SQL_SUCCESS, SQL_NO_DATA]: dbError(db)
|
||||
|
||||
proc sqlGetDBMS(db: var DbConn): string {.
|
||||
@@ -304,7 +304,7 @@ iterator instantRows*(db: var DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect, WriteDbEffect].} =
|
||||
## Same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within the iterator body.
|
||||
## on demand using `[]`. Returned handle is valid only within the iterator body.
|
||||
var
|
||||
rowRes: Row = @[]
|
||||
sz: TSqlLen = 0
|
||||
|
||||
@@ -271,7 +271,7 @@ iterator instantRows*(db: DbConn, query: SqlQuery,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect].} =
|
||||
## same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within iterator body.
|
||||
## on demand using `[]`. Returned handle is valid only within iterator body.
|
||||
setupSingeRowQuery(db, query, args)
|
||||
fetchinstantRows(db)
|
||||
|
||||
@@ -279,7 +279,7 @@ iterator instantRows*(db: DbConn, stmtName: SqlPrepared,
|
||||
args: varargs[string, `$`]): InstantRow
|
||||
{.tags: [ReadDbEffect].} =
|
||||
## same as fastRows but returns a handle that can be used to get column text
|
||||
## on demand using []. Returned handle is valid only within iterator body.
|
||||
## on demand using `[]`. Returned handle is valid only within iterator body.
|
||||
setupSingeRowQuery(db, stmtName, args)
|
||||
fetchinstantRows(db)
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ proc toLangSymbol*(linkText: PRstNode): LangSymbol =
|
||||
##
|
||||
## This proc should be kept in sync with the `renderTypes` proc from
|
||||
## ``compiler/typesrenderer.nim``.
|
||||
assert linkText.kind in {rnRef, rnInner}
|
||||
assert linkText.kind in {rnRstRef, rnInner}
|
||||
|
||||
const NimDefs = ["proc", "func", "macro", "method", "iterator",
|
||||
"template", "converter", "const", "type", "var",
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
## using simple plaintext representation.
|
||||
##
|
||||
## This module is also embedded into Nim compiler; the compiler can output
|
||||
## the result to HTML [#html]_ or Latex [#latex]_.
|
||||
## the result to HTML \[#html] or Latex \[#latex].
|
||||
##
|
||||
## .. [#html] commands `nim doc`:cmd: for ``*.nim`` files and
|
||||
## \[#html] commands `nim doc`:cmd: for ``*.nim`` files and
|
||||
## `nim rst2html`:cmd: for ``*.rst`` files
|
||||
##
|
||||
## .. [#latex] commands `nim doc2tex`:cmd: for ``*.nim`` and
|
||||
## \[#latex] commands `nim doc2tex`:cmd: for ``*.nim`` and
|
||||
## `nim rst2tex`:cmd: for ``*.rst``.
|
||||
##
|
||||
## If you are new to Markdown/RST please consider reading the following:
|
||||
@@ -84,8 +84,8 @@
|
||||
##
|
||||
## Additional Nim-specific features:
|
||||
##
|
||||
## * directives: ``code-block`` [cmp:Sphinx]_, ``title``,
|
||||
## ``index`` [cmp:Sphinx]_
|
||||
## * directives: ``code-block`` \[cmp:Sphinx], ``title``,
|
||||
## ``index`` \[cmp:Sphinx]
|
||||
## * predefined roles
|
||||
## - ``:nim:`` (default), ``:c:`` (C programming language),
|
||||
## ``:python:``, ``:yaml:``, ``:java:``, ``:cpp:`` (C++), ``:csharp`` (C#).
|
||||
@@ -99,9 +99,9 @@
|
||||
## - ``:cmd:`` for commands and common shells syntax
|
||||
## - ``:console:`` the same for interactive sessions
|
||||
## (commands should be prepended by ``$``)
|
||||
## - ``:program:`` for executable names [cmp:Sphinx]_
|
||||
## - ``:program:`` for executable names \[cmp:Sphinx]
|
||||
## (one can just use ``:cmd:`` on single word)
|
||||
## - ``:option:`` for command line options [cmp:Sphinx]_
|
||||
## - ``:option:`` for command line options \[cmp:Sphinx]
|
||||
## - ``:tok:``, a role for highlighting of programming language tokens
|
||||
## * ***triple emphasis*** (bold and italic) using \*\*\*
|
||||
## * ``:idx:`` role for \`interpreted text\` to include the link to this
|
||||
@@ -115,7 +115,7 @@
|
||||
## Here the dummy `//` will disappear, while options `compile`:option:
|
||||
## and `doc`:option: will be left in the final document.
|
||||
##
|
||||
## .. [cmp:Sphinx] similar but different from the directives of
|
||||
## \[cmp:Sphinx] similar but different from the directives of
|
||||
## Python `Sphinx directives`_ and `Sphinx roles`_ extensions
|
||||
##
|
||||
## .. _`extra features`:
|
||||
@@ -1458,7 +1458,7 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode =
|
||||
newSons = n.sons
|
||||
result = newRstNode(newKind, newSons)
|
||||
else: # some link that will be resolved in `resolveSubs`
|
||||
newKind = rnRef
|
||||
newKind = rnRstRef
|
||||
result = newRstNode(newKind, sons=newSons, info=n.info)
|
||||
elif match(p, p.idx, ":w:"):
|
||||
# a role:
|
||||
@@ -1552,7 +1552,7 @@ proc parseWordOrRef(p: var RstParser, father: PRstNode) =
|
||||
while currentTok(p).kind in {tkWord, tkPunct}:
|
||||
if currentTok(p).kind == tkPunct:
|
||||
if isInlineMarkupEnd(p, "_", exact=true):
|
||||
reference = newRstNode(rnRef, info=lineInfo(p, saveIdx))
|
||||
reference = newRstNode(rnRstRef, info=lineInfo(p, saveIdx))
|
||||
break
|
||||
if not validRefnamePunct(currentTok(p).symbol):
|
||||
break
|
||||
@@ -1746,7 +1746,9 @@ proc parseMarkdownCodeblock(p: var RstParser): PRstNode =
|
||||
defaultCodeLangNim(p, result)
|
||||
|
||||
proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool =
|
||||
var desc, link = ""
|
||||
# Parses Markdown link. If it's Pandoc auto-link then its second
|
||||
# son (target) will be in tokenized format (rnInner with leafs).
|
||||
var desc = newRstNode(rnInner)
|
||||
var i = p.idx
|
||||
|
||||
var parensStack: seq[char]
|
||||
@@ -1754,31 +1756,59 @@ proc parseMarkdownLink(p: var RstParser; father: PRstNode): bool =
|
||||
parensStack.setLen 0
|
||||
inc i # skip begin token
|
||||
while true:
|
||||
if p.tok[i].kind in {tkEof, tkIndent}: return false
|
||||
if p.tok[i].kind == tkEof: return false
|
||||
if p.tok[i].kind == tkIndent and p.tok[i+1].kind == tkIndent:
|
||||
return false
|
||||
let isClosing = checkParen(p.tok[i], parensStack)
|
||||
if p.tok[i].symbol == endToken and not isClosing:
|
||||
break
|
||||
dest.add p.tok[i].symbol
|
||||
let symbol = if p.tok[i].kind == tkIndent: " " else: p.tok[i].symbol
|
||||
when dest is string: dest.add symbol
|
||||
else: dest.add newLeaf(symbol)
|
||||
inc i
|
||||
inc i # skip end token
|
||||
|
||||
parse("]", desc)
|
||||
if p.tok[i].symbol != "(": return false
|
||||
let linkIdx = i + 1
|
||||
parse(")", link)
|
||||
# only commit if we detected no syntax error:
|
||||
let protocol = safeProtocol(link)
|
||||
if link == "":
|
||||
result = false
|
||||
rstMessage(p, mwBrokenLink, protocol,
|
||||
p.tok[linkIdx].line, p.tok[linkIdx].col)
|
||||
else:
|
||||
let child = newRstNode(rnHyperlink)
|
||||
child.add desc
|
||||
child.add link
|
||||
father.add child
|
||||
if p.tok[i].symbol == "(":
|
||||
var link = ""
|
||||
let linkIdx = i + 1
|
||||
parse(")", link)
|
||||
# only commit if we detected no syntax error:
|
||||
let protocol = safeProtocol(link)
|
||||
if link == "":
|
||||
result = false
|
||||
rstMessage(p, mwBrokenLink, protocol,
|
||||
p.tok[linkIdx].line, p.tok[linkIdx].col)
|
||||
else:
|
||||
let child = newRstNode(rnHyperlink)
|
||||
child.add newLeaf(desc.addNodes)
|
||||
child.add link
|
||||
father.add child
|
||||
p.idx = i
|
||||
result = true
|
||||
elif roPreferMarkdown in p.s.options:
|
||||
# Use Pandoc's implicit_header_references extension
|
||||
var n = newRstNode(rnPandocRef)
|
||||
if p.tok[i].symbol == "[":
|
||||
var link = newRstNode(rnInner)
|
||||
let targetIdx = i + 1
|
||||
parse("]", link)
|
||||
n.add desc
|
||||
if link.len != 0: # [description][target]
|
||||
n.add link
|
||||
n.info = lineInfo(p, targetIdx)
|
||||
else: # [description=target][]
|
||||
n.add desc
|
||||
n.info = lineInfo(p, p.idx + 1)
|
||||
else: # [description=target]
|
||||
n.add desc
|
||||
n.add desc # target is the same as description
|
||||
n.info = lineInfo(p, p.idx + 1)
|
||||
father.add n
|
||||
p.idx = i
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc getFootnoteType(label: PRstNode): (FootnoteType, int) =
|
||||
if label.sons.len >= 1 and label.sons[0].kind == rnLeaf and
|
||||
@@ -3510,6 +3540,13 @@ proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) =
|
||||
proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
# Associate this link alias with its target and change node kind to
|
||||
# rnHyperlink or rnInternalRef appropriately.
|
||||
var desc, alias: PRstNode
|
||||
if n.kind == rnPandocRef: # link like [desc][alias]
|
||||
desc = n.sons[0]
|
||||
alias = n.sons[1]
|
||||
else: # n.kind == rnRstRef, link like `desc=alias`_
|
||||
desc = n
|
||||
alias = n
|
||||
type LinkDef = object
|
||||
ar: AnchorRule
|
||||
priority: int
|
||||
@@ -3521,14 +3558,13 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
if result == 0:
|
||||
result = cmp(x.target, y.target)
|
||||
var foundLinks: seq[LinkDef]
|
||||
let text = newRstNode(rnInner, n.sons)
|
||||
let refn = rstnodeToRefname(n)
|
||||
let refn = rstnodeToRefname(alias)
|
||||
var hyperlinks = findRef(s, refn)
|
||||
for y in hyperlinks:
|
||||
foundLinks.add LinkDef(ar: arHyperlink, priority: refPriority(y.kind),
|
||||
target: y.value, info: y.info,
|
||||
tooltip: "(" & $y.kind & ")")
|
||||
let substRst = findMainAnchorRst(s, text.addNodes, n.info)
|
||||
let substRst = findMainAnchorRst(s, alias.addNodes, n.info)
|
||||
for subst in substRst:
|
||||
foundLinks.add LinkDef(ar: arInternalRst, priority: subst.priority,
|
||||
target: newLeaf(subst.target.anchor),
|
||||
@@ -3536,19 +3572,19 @@ proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
|
||||
tooltip: "(" & $subst.anchorType & ")")
|
||||
# find anchors automatically generated from Nim symbols
|
||||
if roNimFile in s.options:
|
||||
let substNim = findMainAnchorNim(s, signature=text, n.info)
|
||||
let substNim = findMainAnchorNim(s, signature=alias, n.info)
|
||||
for subst in substNim:
|
||||
foundLinks.add LinkDef(ar: arNim, priority: subst.priority,
|
||||
target: newLeaf(subst.refname),
|
||||
info: subst.info, tooltip: subst.tooltip)
|
||||
foundLinks.sort(cmp = cmp, order = Descending)
|
||||
let linkText = addNodes(n)
|
||||
let linkText = addNodes(desc)
|
||||
if foundLinks.len >= 1:
|
||||
let kind = if foundLinks[0].ar == arHyperlink: rnHyperlink
|
||||
elif foundLinks[0].ar == arNim: rnNimdocRef
|
||||
else: rnInternalRef
|
||||
result = newRstNode(kind)
|
||||
result.sons = @[text, foundLinks[0].target]
|
||||
result.sons = @[newRstNode(rnInner, desc.sons), foundLinks[0].target]
|
||||
if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip
|
||||
if foundLinks.len > 1: # report ambiguous link
|
||||
var targets = newSeq[string]()
|
||||
@@ -3585,7 +3621,7 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode =
|
||||
if e != "": result = newLeaf(e)
|
||||
else: rstMessage(s.filenames, s.msgHandler, n.info,
|
||||
mwUnknownSubstitution, key)
|
||||
of rnRef:
|
||||
of rnRstRef, rnPandocRef:
|
||||
result = resolveLink(s, n)
|
||||
of rnFootnote:
|
||||
var (fnType, num) = getFootnoteType(n.sons[0])
|
||||
|
||||
@@ -49,7 +49,10 @@ type
|
||||
rnCitation, # similar to footnote, so use rnFootnote instead
|
||||
rnFootnoteGroup, # footnote group - exists for a purely stylistic
|
||||
# reason: to display a few footnotes as 1 block
|
||||
rnStandaloneHyperlink, rnHyperlink, rnRef, rnInternalRef, rnFootnoteRef,
|
||||
rnStandaloneHyperlink, rnHyperlink,
|
||||
rnRstRef, # RST reference like `section name`_
|
||||
rnPandocRef, # Pandoc Markdown reference like [section name]
|
||||
rnInternalRef, rnFootnoteRef,
|
||||
rnNimdocRef, # reference to automatically generated Nim symbol
|
||||
rnDirective, # a general directive
|
||||
rnDirArg, # a directive argument (for some directives).
|
||||
@@ -110,7 +113,7 @@ type
|
||||
## auto-numbered ones without a label)
|
||||
of rnMarkdownBlockQuoteItem:
|
||||
quotationDepth*: int ## number of characters in line prefix
|
||||
of rnRef, rnSubstitutionReferences,
|
||||
of rnRstRef, rnPandocRef, rnSubstitutionReferences,
|
||||
rnInterpretedText, rnField, rnInlineCode, rnCodeBlock, rnFootnoteRef:
|
||||
info*: TLineInfo ## To have line/column info for warnings at
|
||||
## nodes that are post-processed after parsing
|
||||
@@ -281,7 +284,7 @@ proc renderRstToRst(d: var RenderContext, n: PRstNode, result: var string) =
|
||||
inc(d.indent, 2)
|
||||
renderRstSons(d, n, result)
|
||||
dec(d.indent, 2)
|
||||
of rnRef:
|
||||
of rnRstRef:
|
||||
result.add("`")
|
||||
renderRstSons(d, n, result)
|
||||
result.add("`_")
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
##
|
||||
## * The same goes for footnotes/citations links: they point to themselves.
|
||||
## No backreferences are generated since finding all references of a footnote
|
||||
## can be done by simply searching for [footnoteName].
|
||||
## can be done by simply searching for ``[footnoteName]``.
|
||||
|
||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||
algorithm, parseutils, std/strbasics
|
||||
@@ -1372,7 +1372,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
"</div>   $1\n</div>\n",
|
||||
"\\item[\\textsuperscript{[$3]}]$2 $1\n",
|
||||
[body, n.anchor.idS, mark, n.anchor])
|
||||
of rnRef:
|
||||
of rnPandocRef:
|
||||
renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false)
|
||||
of rnRstRef:
|
||||
renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=false)
|
||||
of rnStandaloneHyperlink:
|
||||
renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=true)
|
||||
|
||||
@@ -377,7 +377,7 @@ proc `$`*(ms: MemSlice): string {.inline.} =
|
||||
copyMem(addr(result[0]), ms.data, ms.size)
|
||||
|
||||
iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline.} =
|
||||
## Iterates over [optional `eat`] `delim`-delimited slices in MemFile `mfile`.
|
||||
## Iterates over \[optional `eat`] `delim`-delimited slices in MemFile `mfile`.
|
||||
##
|
||||
## Default parameters parse lines ending in either Unix(\\l) or Windows(\\r\\l)
|
||||
## style on on a line-by-line basis. I.e., not every line needs the same ending.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
## This file contains an implementation of the Schubfach algorithm as described in
|
||||
##
|
||||
## [1] Raffaello Giulietti, "The Schubfach way to render doubles",
|
||||
## \[1] Raffaello Giulietti, "The Schubfach way to render doubles",
|
||||
## https://drive.google.com/open?id=1luHhyQF9zKlM8yJ1nebU0OgVYhfC6CBN
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ proc max*[T](x: openArray[T]): T =
|
||||
|
||||
|
||||
proc clamp*[T](x, a, b: T): T =
|
||||
## Limits the value `x` within the interval [a, b].
|
||||
## Limits the value `x` within the interval \[a, b].
|
||||
## This proc is equivalent to but faster than `max(a, min(b, x))`.
|
||||
##
|
||||
## .. warning:: `a <= b` is assumed and will not be checked (currently).
|
||||
|
||||
@@ -56,6 +56,9 @@
|
||||
<ul class="simple"><li><a class="reference" id="next-header-and-so-on_toc" href="#next-header-and-so-on">And so on</a></li>
|
||||
</ul></ul><li><a class="reference" id="more-headers_toc" href="#more-headers">More headers</a></li>
|
||||
<ul class="simple"><li><a class="reference" id="more-headers-up-to-level-6_toc" href="#more-headers-up-to-level-6">Up to level 6</a></li>
|
||||
</ul><li><a class="reference" id="pandoc-markdown_toc" href="#pandoc-markdown">Pandoc Markdown</a></li>
|
||||
<ul class="simple"><li><a class="reference" id="pandoc-markdown-link-name-syntax_toc" href="#pandoc-markdown-link-name-syntax">Link name syntax</a></li>
|
||||
<li><a class="reference" id="pandoc-markdown-symbols-documentation_toc" href="#pandoc-markdown-symbols-documentation">Symbols documentation</a></li>
|
||||
</ul><li>
|
||||
<details open>
|
||||
<summary><a class="reference reference-toplevel" href="#7" id="57">Types</a></summary>
|
||||
@@ -229,7 +232,27 @@
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch proc</a>.</p>
|
||||
<p>Ref. type like <a class="reference internal nimdoc" title="type G" href="#G">G</a> and <a class="reference internal nimdoc" title="type G" href="#G">type G</a> and <a class="reference internal nimdoc" title="type G" href="#G">G[T]</a> and <a class="reference internal nimdoc" title="type G" href="#G">type G*[T]</a>.</p>
|
||||
<p>Group ref. with capital letters works: <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fN11</a> or <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fn11</a> </p>
|
||||
Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">[]</a> is the same as <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`(G[T])</a> because there are no overloads. The full form: <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`*[T](x: G[T]): T</a>Ref. <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">[]=</a> aka <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">`[]=`(G[T], int, T)</a>.Ref. <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">$</a> aka <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc $</a> or <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc `$`</a>.Ref. <a class="reference internal nimdoc" title="proc `$`[T](a: ref SomeType): string" href="#$,ref.SomeType">$(a: ref SomeType)</a>.Ref. <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">foo_bar</a> aka <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">iterator foo_bar_</a>.Ref. <a class="reference internal nimdoc" title="proc fn[T; U, V: SomeFloat]()" href="#fn">fn[T; U,V: SomeFloat]()</a>.Ref. <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">'big</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">func `'big`</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">`'big`(string)</a>.</p>
|
||||
Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">[]</a> is the same as <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`(G[T])</a> because there are no overloads. The full form: <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`*[T](x: G[T]): T</a>Ref. <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">[]=</a> aka <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">`[]=`(G[T], int, T)</a>.Ref. <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">$</a> aka <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc $</a> or <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc `$`</a>.Ref. <a class="reference internal nimdoc" title="proc `$`[T](a: ref SomeType): string" href="#$,ref.SomeType">$(a: ref SomeType)</a>.Ref. <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">foo_bar</a> aka <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">iterator foo_bar_</a>.Ref. <a class="reference internal nimdoc" title="proc fn[T; U, V: SomeFloat]()" href="#fn">fn[T; U,V: SomeFloat]()</a>.Ref. <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">'big</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">func `'big`</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">`'big`(string)</a>.
|
||||
<h1><a class="toc-backref" id="pandoc-markdown" href="#pandoc-markdown">Pandoc Markdown</a></h1><p>Now repeat all the auto links of above in Pandoc Markdown Syntax.</p>
|
||||
<p>Ref group <a class="reference internal nimdoc" title="proc fn2 (3 overloads)" href="#fn2-procs-all">fn2</a> or specific function like <a class="reference internal nimdoc" title="proc fn2()" href="#fn2">fn2()</a> or <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2( int )</a> or <a class="reference internal nimdoc" title="proc fn2(x: int; y: float)" href="#fn2,int,float">fn2(int, float)</a>.</p>
|
||||
<p>Ref generics like this: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch(openArray[T], K, proc (T, K))</a> or <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">proc binarySearch(openArray[T], K, proc (T, K))</a> or in different style: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">proc binarysearch(openarray[T], K, proc(T, K))</a>. Can be combined with export symbols and type parameters: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarysearch*[T, K](openArray[T], K, proc (T, K))</a>. With spaces <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binary search</a>.</p>
|
||||
<p>Note that <tt class="docutils literal"><span class="pre"><span class="Keyword">proc</span></span></tt> can be used in postfix form: <a class="reference internal nimdoc" title="proc binarySearch[T, K](a: openArray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.}): int" href="#binarySearch,openArray[T],K,proc(T,K)">binarySearch proc</a>.</p>
|
||||
<p>Ref. type like <a class="reference internal nimdoc" title="type G" href="#G">G</a> and <a class="reference internal nimdoc" title="type G" href="#G">type G</a> and <a class="reference internal nimdoc" title="type G" href="#G">G[T]</a> and <a class="reference internal nimdoc" title="type G" href="#G">type G*[T]</a>.</p>
|
||||
<p>Group ref. with capital letters works: <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fN11</a> or <a class="reference internal nimdoc" title="proc fN11 (2 overloads)" href="#fN11-procs-all">fn11</a></p>
|
||||
<p>Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">`[]`</a> is the same as <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`(G[T])</a> because there are no overloads. The full form: <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">proc `[]`*[T](x: G[T]): T</a> Ref. <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">`[]=`</a> aka <a class="reference internal nimdoc" title="proc `[]=`[T](a: var G[T]; index: int; value: T)" href="#[]=,G[T],int,T">`[]=`(G[T], int, T)</a>. Ref. <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">$</a> aka <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc $</a> or <a class="reference internal nimdoc" title="proc $ (2 overloads)" href="#$-procs-all">proc `$`</a>. Ref. <a class="reference internal nimdoc" title="proc `$`[T](a: ref SomeType): string" href="#$,ref.SomeType">$(a: ref SomeType)</a>. Ref. <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">foo_bar</a> aka <a class="reference internal nimdoc" title="iterator fooBar(a: seq[SomeType]): int" href="#fooBar.i,seq[SomeType]">iterator foo_bar_</a>. Ref. <a class="reference internal nimdoc" title="proc fn[T; U, V: SomeFloat]()" href="#fn">fn[T; U,V: SomeFloat]()</a>. Ref. <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">'big</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">func `'big`</a> or <a class="reference internal nimdoc" title="proc `'big`(a: string): SomeType" href="#'big,string">`'big`(string)</a>.</p>
|
||||
|
||||
<h2><a class="toc-backref" id="pandoc-markdown-link-name-syntax" href="#pandoc-markdown-link-name-syntax">Link name syntax</a></h2><p>Pandoc Markdown has synax for changing text of links: Ref. <a class="reference internal nimdoc" title="proc `[]`[T](x: G[T]): T" href="#[],G[T]">this proc</a> or <a class="reference internal nimdoc" title="type G" href="#G">another symbol</a>.</p>
|
||||
|
||||
<h2><a class="toc-backref" id="pandoc-markdown-symbols-documentation" href="#pandoc-markdown-symbols-documentation">Symbols documentation</a></h2><p>Let us repeat auto links from symbols section below:</p>
|
||||
<p>There is also variant <a class="reference internal nimdoc" title="proc f(x: G[string])" href="#f,G[string]">f(G[string])</a>. See also <a class="reference internal nimdoc" title="proc f(x: G[int])" href="#f,G[int]">f(G[int])</a>.</p>
|
||||
</p>
|
||||
<div class="section" id="7">
|
||||
<h1><a class="toc-backref" href="#7">Types</a></h1>
|
||||
<dl class="item">
|
||||
|
||||
@@ -36,3 +36,6 @@ Next header subdir/subdir_b/utils.html#this-is-now-a-header-next-header Next h
|
||||
And so on subdir/subdir_b/utils.html#next-header-and-so-on And so on
|
||||
More headers subdir/subdir_b/utils.html#more-headers More headers
|
||||
Up to level 6 subdir/subdir_b/utils.html#more-headers-up-to-level-6 Up to level 6
|
||||
Pandoc Markdown subdir/subdir_b/utils.html#pandoc-markdown Pandoc Markdown
|
||||
Link name syntax subdir/subdir_b/utils.html#pandoc-markdown-link-name-syntax Link name syntax
|
||||
Symbols documentation subdir/subdir_b/utils.html#pandoc-markdown-symbols-documentation Symbols documentation
|
||||
|
||||
@@ -79,7 +79,9 @@ func fn9*(a: int): int = 42 ## comment
|
||||
func fn10*(a: int): int = a ## comment
|
||||
|
||||
# Note capital letter N will be handled correctly in
|
||||
# group references like fN11_ or fn11_:
|
||||
# group references like fN11_ or fn11_
|
||||
# (or [fN11] or [fn11] in Markdown Syntax):
|
||||
|
||||
func fN11*() = discard
|
||||
func fN11*(x: int) = discard
|
||||
|
||||
@@ -160,3 +162,52 @@ proc fn*[T; U, V: SomeFloat]() = discard
|
||||
## Ref. `'big`_ or `func \`'big\``_ or `\`'big\`(string)`_.
|
||||
|
||||
func `'big`*(a: string): SomeType = discard
|
||||
|
||||
##[
|
||||
|
||||
Pandoc Markdown
|
||||
===============
|
||||
|
||||
Now repeat all the auto links of above in Pandoc Markdown Syntax.
|
||||
|
||||
Ref group [fn2] or specific function like [fn2()]
|
||||
or [fn2( int )] or [fn2(int,
|
||||
float)].
|
||||
|
||||
Ref generics like this: [binarySearch] or [binarySearch(openArray[T], K,
|
||||
proc (T, K))] or [proc binarySearch(openArray[T], K, proc (T, K))] or
|
||||
in different style: [proc binarysearch(openarray[T], K, proc(T, K))].
|
||||
Can be combined with export symbols and type parameters:
|
||||
[binarysearch*[T, K](openArray[T], K, proc (T, K))].
|
||||
With spaces [binary search].
|
||||
|
||||
Note that `proc` can be used in postfix form: [binarySearch proc].
|
||||
|
||||
Ref. type like [G] and [type G] and [G[T]] and [type G*[T]].
|
||||
|
||||
Group ref. with capital letters works: [fN11] or [fn11]
|
||||
|
||||
Ref. [`[]`] is the same as [proc `[]`(G[T])] because there are no
|
||||
overloads. The full form: [proc `[]`*[T](x: G[T]): T]
|
||||
Ref. [`[]=`] aka [`[]=`(G[T], int, T)].
|
||||
Ref. [$] aka [proc $] or [proc `$`].
|
||||
Ref. [$(a: ref SomeType)].
|
||||
Ref. [foo_bar] aka [iterator foo_bar_].
|
||||
Ref. [fn[T; U,V: SomeFloat]()].
|
||||
Ref. ['big] or [func `'big`] or [`'big`(string)].
|
||||
|
||||
Link name syntax
|
||||
----------------
|
||||
|
||||
Pandoc Markdown has synax for changing text of links:
|
||||
Ref. [this proc][`[]`] or [another symbol][G[T]].
|
||||
|
||||
Symbols documentation
|
||||
---------------------
|
||||
|
||||
Let us repeat auto links from symbols section below:
|
||||
|
||||
There is also variant [f(G[string])].
|
||||
See also [f(G[int])].
|
||||
|
||||
]##
|
||||
|
||||
@@ -10,74 +10,101 @@ discard """
|
||||
import ../../lib/packages/docutils/[rstast, rst, dochelpers]
|
||||
import unittest
|
||||
|
||||
proc rstParseTest(text: string): PRstNode =
|
||||
proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
|
||||
arg: string) =
|
||||
doAssert msgkind == mwBrokenLink
|
||||
proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
|
||||
arg: string) =
|
||||
doAssert msgkind == mwBrokenLink
|
||||
|
||||
proc fromRst(text: string): LangSymbol =
|
||||
let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
|
||||
{roNimFile},
|
||||
msgHandler=testMsgHandler)
|
||||
assert r.node.kind == rnRstRef
|
||||
result = toLangSymbol(r.node)
|
||||
|
||||
proc fromMd(text: string): LangSymbol =
|
||||
let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
|
||||
{roPreferMarkdown, roSupportMarkdown, roNimFile},
|
||||
msgHandler=testMsgHandler)
|
||||
result = r.node
|
||||
assert r.node.kind == rnPandocRef
|
||||
assert r.node.len == 2
|
||||
# this son is the target:
|
||||
assert r.node.sons[1].kind == rnInner
|
||||
result = toLangSymbol(r.node.sons[1])
|
||||
|
||||
suite "Integration with Nim":
|
||||
test "simple symbol parsing (shortest form)":
|
||||
let input1 = "g_".rstParseTest
|
||||
check input1.toLangSymbol == LangSymbol(symKind: "", name: "g")
|
||||
let expected = LangSymbol(symKind: "", name: "g")
|
||||
check "g_".fromRst == expected
|
||||
check "[g]".fromMd == expected
|
||||
# test also alternative syntax variants of Pandoc Markdown:
|
||||
check "[g][]".fromMd == expected
|
||||
check "[this symbol][g]".fromMd == expected
|
||||
|
||||
test "simple symbol parsing (group of words)":
|
||||
let input1 = "`Y`_".rstParseTest
|
||||
check input1.toLangSymbol == LangSymbol(symKind: "", name: "Y")
|
||||
#let input1 = "`Y`_".rstParseTest
|
||||
let expected1 = LangSymbol(symKind: "", name: "Y")
|
||||
check "`Y`_".fromRst == expected1
|
||||
check "[Y]".fromMd == expected1
|
||||
|
||||
# this means not a statement 'type', it's a backticked identifier `type`:
|
||||
let input2 = "`type`_".rstParseTest
|
||||
check input2.toLangSymbol == LangSymbol(symKind: "", name: "type")
|
||||
let expected2 = LangSymbol(symKind: "", name: "type")
|
||||
check "`type`_".fromRst == expected2
|
||||
check "[type]".fromMd == expected2
|
||||
|
||||
let input3 = "`[]`_".rstParseTest
|
||||
check input3.toLangSymbol == LangSymbol(symKind: "", name: "[]")
|
||||
let expected3 = LangSymbol(symKind: "", name: "[]")
|
||||
check "`[]`_".fromRst == expected3
|
||||
# Markdown syntax for this case is NOT [[]]
|
||||
check "[`[]`]".fromMd == expected3
|
||||
|
||||
let input4 = "`X Y Z`_".rstParseTest
|
||||
check input4.toLangSymbol == LangSymbol(symKind: "", name: "Xyz")
|
||||
let expected4 = LangSymbol(symKind: "", name: "Xyz")
|
||||
check "`X Y Z`_".fromRst == expected4
|
||||
check "[X Y Z]".fromMd == expected4
|
||||
|
||||
test "simple proc parsing":
|
||||
let input1 = "proc f".rstParseTest
|
||||
check input1.toLangSymbol == LangSymbol(symKind: "proc", name: "f")
|
||||
let expected = LangSymbol(symKind: "proc", name: "f")
|
||||
check "`proc f`_".fromRst == expected
|
||||
check "[proc f]".fromMd == expected
|
||||
|
||||
test "another backticked name":
|
||||
let input1 = """`template \`type\``_""".rstParseTest
|
||||
check input1.toLangSymbol == LangSymbol(symKind: "template", name: "type")
|
||||
let expected = LangSymbol(symKind: "template", name: "type")
|
||||
check """`template \`type\``_""".fromRst == expected
|
||||
# no backslash in Markdown:
|
||||
check """[template `type`]""".fromMd == expected
|
||||
|
||||
test "simple proc parsing with parameters":
|
||||
let input1 = "`proc f*()`_".rstParseTest
|
||||
let input2 = "`proc f()`_".rstParseTest
|
||||
let expected = LangSymbol(symKind: "proc", name: "f",
|
||||
parametersProvided: true)
|
||||
check input1.toLangSymbol == expected
|
||||
check input2.toLangSymbol == expected
|
||||
check "`proc f*()`_".fromRst == expected
|
||||
check "`proc f()`_".fromRst == expected
|
||||
check "[proc f*()]".fromMd == expected
|
||||
check "[proc f()]".fromMd == expected
|
||||
|
||||
test "symbol parsing with 1 parameter":
|
||||
let input = "`f(G[int])`_".rstParseTest
|
||||
let expected = LangSymbol(symKind: "", name: "f",
|
||||
parameters: @[("G[int]", "")],
|
||||
parametersProvided: true)
|
||||
check input.toLangSymbol == expected
|
||||
check "`f(G[int])`_".fromRst == expected
|
||||
check "[f(G[int])]".fromMd == expected
|
||||
|
||||
test "more proc parsing":
|
||||
let input1 = "`proc f[T](x:G[T]):M[T]`_".rstParseTest
|
||||
let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".rstParseTest
|
||||
let input3 = "`proc f*[T](x: G[T]): M[T]`_".rstParseTest
|
||||
let input1 = "`proc f[T](x:G[T]):M[T]`_".fromRst
|
||||
let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".fromRst
|
||||
let input3 = "`proc f*[T](x: G[T]): M[T]`_".fromRst
|
||||
let expected = LangSymbol(symKind: "proc",
|
||||
name: "f",
|
||||
generics: "[T]",
|
||||
parameters: @[("x", "G[T]")],
|
||||
parametersProvided: true,
|
||||
outType: "M[T]")
|
||||
check(input1.toLangSymbol == expected)
|
||||
check(input2.toLangSymbol == expected)
|
||||
check(input3.toLangSymbol == expected)
|
||||
check(input1 == expected)
|
||||
check(input2 == expected)
|
||||
check(input3 == expected)
|
||||
|
||||
test "advanced proc parsing with Nim identifier normalization":
|
||||
let input = """`proc binarySearch*[T, K](a: openarray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int)`_""".rstParseTest
|
||||
let inputRst = """`proc binarySearch*[T, K](a: openarray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int)`_"""
|
||||
let inputMd = """[proc binarySearch*[T, K](a: openarray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int)]"""
|
||||
let expected = LangSymbol(symKind: "proc",
|
||||
name: "binarysearch",
|
||||
generics: "[T,K]",
|
||||
@@ -87,11 +114,12 @@ suite "Integration with Nim":
|
||||
("cmp", "proc(x:T;y:K):int")],
|
||||
parametersProvided: true,
|
||||
outType: "")
|
||||
check(input.toLangSymbol == expected)
|
||||
check(inputRst.fromRst == expected)
|
||||
check(inputMd.fromMd == expected)
|
||||
|
||||
test "the same without proc":
|
||||
let input = """`binarySearch*[T, K](a: openarray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.})`_""".rstParseTest
|
||||
cmp: proc (x: T; y: K): int {.closure.})`_"""
|
||||
let expected = LangSymbol(symKind: "",
|
||||
name: "binarysearch",
|
||||
generics: "[T,K]",
|
||||
@@ -101,27 +129,32 @@ suite "Integration with Nim":
|
||||
("cmp", "proc(x:T;y:K):int")],
|
||||
parametersProvided: true,
|
||||
outType: "")
|
||||
check(input.toLangSymbol == expected)
|
||||
check(input.fromRst == expected)
|
||||
let inputMd = """[binarySearch*[T, K](a: openarray[T]; key: K;
|
||||
cmp: proc (x: T; y: K): int {.closure.})]"""
|
||||
check(inputMd.fromMd == expected)
|
||||
|
||||
test "operator $ with and without backticks":
|
||||
let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_""".
|
||||
rstParseTest
|
||||
let input2 = """`func $*[T](a: \`open Array\`[T]): string`_""".
|
||||
rstParseTest
|
||||
let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_"""
|
||||
let input1md = "[func `$`*[T](a: `open Array`[T]): string]"
|
||||
let input2 = """`func $*[T](a: \`open Array\`[T]): string`_"""
|
||||
let input2md = "[func $*[T](a: `open Array`[T]): string]"
|
||||
let expected = LangSymbol(symKind: "func",
|
||||
name: "$",
|
||||
generics: "[T]",
|
||||
parameters: @[("a", "openarray[T]")],
|
||||
parametersProvided: true,
|
||||
outType: "string")
|
||||
check(input1.toLangSymbol == expected)
|
||||
check(input2.toLangSymbol == expected)
|
||||
check input1.fromRst == expected
|
||||
check input2.fromRst == expected
|
||||
check input1md.fromMd == expected
|
||||
check input2md.fromMd == expected
|
||||
|
||||
test "operator [] with and without backticks":
|
||||
let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_""".
|
||||
rstParseTest
|
||||
let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_""".
|
||||
rstParseTest
|
||||
let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_"""
|
||||
let input1md = "[func `[]`[T](a: `open Array`[T], idx: int): T]"
|
||||
let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_"""
|
||||
let input2md = "[func [][T](a: `open Array`[T], idx: int): T]"
|
||||
let expected = LangSymbol(symKind: "func",
|
||||
name: "[]",
|
||||
generics: "[T]",
|
||||
@@ -129,21 +162,25 @@ suite "Integration with Nim":
|
||||
("idx", "int")],
|
||||
parametersProvided: true,
|
||||
outType: "T")
|
||||
check(input1.toLangSymbol == expected)
|
||||
check(input2.toLangSymbol == expected)
|
||||
check input1.fromRst == expected
|
||||
check input2.fromRst == expected
|
||||
check input1md.fromMd == expected
|
||||
check input2md.fromMd == expected
|
||||
|
||||
test "postfix symbol specifier #1":
|
||||
let input = """`walkDir iterator`_""".
|
||||
rstParseTest
|
||||
let input = "`walkDir iterator`_"
|
||||
let inputMd = "[walkDir iterator]"
|
||||
let expected = LangSymbol(symKind: "iterator",
|
||||
name: "walkdir")
|
||||
check(input.toLangSymbol == expected)
|
||||
check input.fromRst == expected
|
||||
check inputMd.fromMd == expected
|
||||
|
||||
test "postfix symbol specifier #2":
|
||||
let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_""".
|
||||
rstParseTest
|
||||
let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_""".
|
||||
rstParseTest
|
||||
let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_"""
|
||||
let input1md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
|
||||
let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_"""
|
||||
# note again that ` is needed between 1st and second [
|
||||
let input2md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
|
||||
let expected = LangSymbol(symKind: "func",
|
||||
name: "[]",
|
||||
generics: "[T]",
|
||||
@@ -151,11 +188,16 @@ suite "Integration with Nim":
|
||||
("idx", "int")],
|
||||
parametersProvided: true,
|
||||
outType: "T")
|
||||
check(input1.toLangSymbol == expected)
|
||||
check(input2.toLangSymbol == expected)
|
||||
check input1.fromRst == expected
|
||||
check input2.fromRst == expected
|
||||
check input1md.fromMd == expected
|
||||
check input2md.fromMd == expected
|
||||
|
||||
test "type of type":
|
||||
check ("`CopyFlag enum`_".rstParseTest.toLangSymbol ==
|
||||
LangSymbol(symKind: "type",
|
||||
symTypeKind: "enum",
|
||||
name: "Copyflag"))
|
||||
let inputRst = "`CopyFlag enum`_"
|
||||
let inputMd = "[CopyFlag enum]"
|
||||
let expected = LangSymbol(symKind: "type",
|
||||
symTypeKind: "enum",
|
||||
name: "Copyflag")
|
||||
check inputRst.fromRst == expected
|
||||
check inputMd.fromMd == expected
|
||||
|
||||
@@ -1173,7 +1173,7 @@ suite "Warnings":
|
||||
lastParagraph
|
||||
"""
|
||||
var warnings = new seq[string]
|
||||
let output = input.toAst(warnings=warnings)
|
||||
let output = input.toAst(rstOptions=preferRst, warnings=warnings)
|
||||
check(warnings[] == @[
|
||||
"input(3, 14) Warning: broken link 'citation-som'",
|
||||
"input(5, 7) Warning: broken link 'a broken Link'",
|
||||
@@ -1199,7 +1199,7 @@ suite "Warnings":
|
||||
rnParagraph
|
||||
rnLeaf 'here'
|
||||
rnLeaf ' '
|
||||
rnRef
|
||||
rnRstRef
|
||||
rnLeaf 'brokenLink'
|
||||
""")
|
||||
removeFile("other.rst")
|
||||
@@ -1558,7 +1558,7 @@ suite "RST inline markup":
|
||||
|
||||
test "no punctuation in the end of a standalone URI is allowed":
|
||||
check(dedent"""
|
||||
[see (http://no.org)], end""".toAst ==
|
||||
[see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
|
||||
dedent"""
|
||||
rnInner
|
||||
rnLeaf '['
|
||||
@@ -1606,6 +1606,19 @@ suite "RST inline markup":
|
||||
rnLeaf 'end'
|
||||
""")
|
||||
|
||||
test "Markdown-style link can be split to a few lines":
|
||||
check(dedent"""
|
||||
is [term-rewriting
|
||||
macros](manual.html#term-rewriting-macros)""".toAst ==
|
||||
dedent"""
|
||||
rnInner
|
||||
rnLeaf 'is'
|
||||
rnLeaf ' '
|
||||
rnHyperlink
|
||||
rnLeaf 'term-rewriting macros'
|
||||
rnLeaf 'manual.html#term-rewriting-macros'
|
||||
""")
|
||||
|
||||
test "URL with balanced parentheses (Markdown rule)":
|
||||
# 2 balanced parens, 1 unbalanced:
|
||||
check(dedent"""
|
||||
|
||||
@@ -983,7 +983,7 @@ Test1
|
||||
|
||||
Ref. [#note]_
|
||||
"""
|
||||
let output1 = input1.toHtml
|
||||
let output1 = input1.toHtml(preferRst)
|
||||
doAssert output1.count(">[1]</a>") == 1
|
||||
doAssert output1.count(">[2]</a>") == 2
|
||||
doAssert "href=\"#footnote-note\"" in output1
|
||||
@@ -1001,7 +1001,7 @@ Test1
|
||||
|
||||
Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_.
|
||||
"""
|
||||
let output2 = input2.toHtml
|
||||
let output2 = input2.toHtml(preferRst)
|
||||
doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_."
|
||||
|
||||
# check that auto-symbol footnotes work:
|
||||
@@ -1017,7 +1017,7 @@ Test1
|
||||
|
||||
And [*]_.
|
||||
"""
|
||||
let output3 = input3.toHtml
|
||||
let output3 = input3.toHtml(preferRst)
|
||||
# both references and footnotes. Footnotes have link to themselves.
|
||||
doAssert output3.count("href=\"#footnotesym-1\">[*]</a>") == 2
|
||||
doAssert output3.count("href=\"#footnotesym-2\">[**]</a>") == 2
|
||||
@@ -1047,7 +1047,7 @@ Test1
|
||||
|
||||
Ref. [#note]_ and [#]_ and [#]_.
|
||||
"""
|
||||
let output4 = input4.toHtml
|
||||
let output4 = input4.toHtml(preferRst)
|
||||
doAssert ">[-1]" notin output1
|
||||
let order = @[
|
||||
"footnote-3", "[3]", "Manual1.",
|
||||
@@ -1072,7 +1072,7 @@ Test1
|
||||
Ref. [#note]_
|
||||
"""
|
||||
var error5 = new string
|
||||
let output5 = input5.toHtml(error=error5)
|
||||
let output5 = input5.toHtml(preferRst, error=error5)
|
||||
check(error5[] == "input(1, 1) Error: mismatch in number of footnotes " &
|
||||
"and their refs: 1 (lines 2) != 0 (lines ) for auto-numbered " &
|
||||
"footnotes")
|
||||
@@ -1086,7 +1086,7 @@ Test1
|
||||
Ref. [*]_
|
||||
"""
|
||||
var error6 = new string
|
||||
let output6 = input6.toHtml(error=error6)
|
||||
let output6 = input6.toHtml(preferRst, error=error6)
|
||||
check(error6[] == "input(1, 1) Error: mismatch in number of footnotes " &
|
||||
"and their refs: 1 (lines 3) != 2 (lines 2, 6) for auto-symbol " &
|
||||
"footnotes")
|
||||
@@ -1096,7 +1096,7 @@ Test1
|
||||
|
||||
Ref. [some:citation-2020]_.
|
||||
"""
|
||||
let output7 = input7.toHtml
|
||||
let output7 = input7.toHtml(preferRst)
|
||||
doAssert output7.count("href=\"#citation-somecoloncitationminus2020\"") == 2
|
||||
doAssert output7.count("[Some:CITATION-2020]") == 1
|
||||
doAssert output7.count("[some:citation-2020]") == 1
|
||||
@@ -1109,7 +1109,7 @@ Test1
|
||||
Ref. [som]_.
|
||||
"""
|
||||
var warnings8 = new seq[string]
|
||||
let output8 = input8.toHtml(warnings=warnings8)
|
||||
let output8 = input8.toHtml(preferRst, warnings=warnings8)
|
||||
check(warnings8[] == @["input(3, 7) Warning: broken link 'citation-som'"])
|
||||
|
||||
# check that footnote group does not break parsing of other directives:
|
||||
@@ -1145,7 +1145,7 @@ Test1
|
||||
|
||||
.. [Third] Citation.
|
||||
"""
|
||||
let output10 = input10.toHtml
|
||||
let output10 = input10.toHtml(preferRst)
|
||||
doAssert output10.count("<hr class=\"footnote\">" &
|
||||
"<div class=\"footnote-group\">") == 3
|
||||
doAssert output10.count("<div class=\"footnote-label\">") == 3
|
||||
@@ -1165,7 +1165,7 @@ Test1
|
||||
.. [#] Body3
|
||||
.. [2] Body2.
|
||||
"""
|
||||
let output12 = input12.toHtml
|
||||
let output12 = input12.toHtml(preferRst)
|
||||
let orderAuto = @[
|
||||
"#footnoteauto-1", "[1]",
|
||||
"#footnoteauto-2", "[3]",
|
||||
|
||||
Reference in New Issue
Block a user