diff options
author | Andrey Makarov <ph.makarov@gmail.com> | 2022-09-04 21:52:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-04 14:52:21 -0400 |
commit | cde6b2aab8f67291eca5375a067f97e98b7593ee (patch) | |
tree | 67f7e577b5208e823cb278dd8503d090a3e10dac | |
parent | b931e74a59f6e62cd1817a34b57b25ef378c8679 (diff) | |
download | Nim-cde6b2aab8f67291eca5375a067f97e98b7593ee.tar.gz |
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
-rw-r--r-- | doc/basicopt.txt | 2 | ||||
-rw-r--r-- | doc/contributing.md | 6 | ||||
-rw-r--r-- | doc/docgen.md | 4 | ||||
-rw-r--r-- | doc/idetools.md | 28 | ||||
-rw-r--r-- | doc/intern.md | 2 | ||||
-rw-r--r-- | doc/manual.md | 8 | ||||
-rw-r--r-- | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | lib/impure/db_mysql.nim | 6 | ||||
-rw-r--r-- | lib/impure/db_odbc.nim | 4 | ||||
-rw-r--r-- | lib/impure/db_postgres.nim | 4 | ||||
-rw-r--r-- | lib/packages/docutils/dochelpers.nim | 2 | ||||
-rw-r--r-- | lib/packages/docutils/rst.nim | 104 | ||||
-rw-r--r-- | lib/packages/docutils/rstast.nim | 9 | ||||
-rw-r--r-- | lib/packages/docutils/rstgen.nim | 6 | ||||
-rw-r--r-- | lib/pure/memfiles.nim | 2 | ||||
-rw-r--r-- | lib/std/private/schubfach.nim | 2 | ||||
-rw-r--r-- | lib/system/comparisons.nim | 2 | ||||
-rw-r--r-- | nimdoc/testproject/expected/subdir/subdir_b/utils.html | 25 | ||||
-rw-r--r-- | nimdoc/testproject/expected/subdir/subdir_b/utils.idx | 3 | ||||
-rw-r--r-- | nimdoc/testproject/subdir/subdir_b/utils.nim | 53 | ||||
-rw-r--r-- | tests/stdlib/tdochelpers.nim | 164 | ||||
-rw-r--r-- | tests/stdlib/trst.nim | 19 | ||||
-rw-r--r-- | tests/stdlib/trstgen.nim | 20 |
23 files changed, 325 insertions, 152 deletions
diff --git a/doc/basicopt.txt b/doc/basicopt.txt index 390fc6fd2..a9aa4b8fa 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -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) diff --git a/doc/contributing.md b/doc/contributing.md index 507abdffc..ba9d4e518 100644 --- a/doc/contributing.md +++ b/doc/contributing.md @@ -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 diff --git a/doc/docgen.md b/doc/docgen.md index a651d0a10..59a99b00f 100644 --- a/doc/docgen.md +++ b/doc/docgen.md @@ -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: diff --git a/doc/idetools.md b/doc/idetools.md index 21a1b1e34..5bfa59442 100644 --- a/doc/idetools.md +++ b/doc/idetools.md @@ -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. diff --git a/doc/intern.md b/doc/intern.md index 61b97f85e..08de0edd6 100644 --- a/doc/intern.md +++ b/doc/intern.md @@ -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:. diff --git a/doc/manual.md b/doc/manual.md index 1cbfe6846..0be2e9edf 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -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 ============================ ============================================== diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 57764410e..61b3a7b43 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 87fd34913..9a98cb9c5 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -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: diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 0ecd8129f..da1b1e9b5 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -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 diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index 82403ab00..e629b7945 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -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) diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim index a11f2bbbb..b85e37983 100644 --- a/lib/packages/docutils/dochelpers.nim +++ b/lib/packages/docutils/dochelpers.nim @@ -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", diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 5d61dc8c3..8ea2b56f3 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -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]) diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index eac3a5e15..05e4ec39e 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -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("`_") diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 32d2d3483..00f1ac19d 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -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) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index f65ca125e..dacb15e17 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -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. diff --git a/lib/std/private/schubfach.nim b/lib/std/private/schubfach.nim index 5b965aaa7..206153a68 100644 --- a/lib/std/private/schubfach.nim +++ b/lib/std/private/schubfach.nim @@ -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 # -------------------------------------------------------------------------------------------------- diff --git a/lib/system/comparisons.nim b/lib/system/comparisons.nim index 7122daa20..daa47fa59 100644 --- a/lib/system/comparisons.nim +++ b/lib/system/comparisons.nim @@ -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). diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index b3d52c4f5..d888a4609 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -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"> diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx index 5c8fee527..007101b37 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx @@ -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 diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index e201a3d38..f535d7f74 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -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])]. + +]## diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim index 8dcb158ca..0ad49427c 100644 --- a/tests/stdlib/tdochelpers.nim +++ b/tests/stdlib/tdochelpers.nim @@ -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 diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index 32917d257..0b6cbc071 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -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""" diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 8e05f80b7..6edacfc24 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -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]", |