summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/docgen.nim154
-rw-r--r--compiler/lineinfos.nim2
-rw-r--r--compiler/typesrenderer.nim66
-rw-r--r--config/nimdoc.cfg11
-rw-r--r--config/nimdoc.tex.cfg10
-rw-r--r--doc/docgen.rst170
-rw-r--r--doc/nimdoc.css4
-rw-r--r--lib/packages/docutils/dochelpers.nim267
-rw-r--r--lib/packages/docutils/rst.nim321
-rw-r--r--lib/packages/docutils/rstast.nim3
-rw-r--r--lib/packages/docutils/rstgen.nim27
-rw-r--r--lib/pure/strutils.nim5
-rw-r--r--nimdoc/test_out_index_dot_html/expected/index.html4
-rw-r--r--nimdoc/testproject/expected/nimdoc.out.css4
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.html297
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.idx14
-rw-r--r--nimdoc/testproject/expected/testproject.html208
-rw-r--r--nimdoc/testproject/expected/theindex.html52
-rw-r--r--nimdoc/testproject/subdir/subdir_b/utils.nim65
-rw-r--r--nimdoc/testproject/subdir/subdir_b/utils_helpers.nim1
-rw-r--r--nimdoc/testproject/subdir/subdir_b/utils_overview.rst8
-rw-r--r--tests/stdlib/tdochelpers.nim155
-rw-r--r--tests/stdlib/trst.nim109
-rw-r--r--tests/stdlib/trstgen.nim19
24 files changed, 1833 insertions, 143 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 1acfc7489..2639840d1 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -13,7 +13,7 @@
 import
   ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
   wordrecg, syntaxes, renderer, lexer,
-  packages/docutils/rst, packages/docutils/rstgen,
+  packages/docutils/[rst, rstgen, dochelpers],
   json, xmltree, trees, types,
   typesrenderer, astalgo, lineinfos, intsets,
   pathutils, tables, nimpaths, renderverbatim, osproc
@@ -44,8 +44,14 @@ type
                          ## runnableExamples).
     substitutions: seq[string]    ## Variable names in `doc.item`...
     sortName: string    ## The string used for sorting in output
+    info: rstast.TLineInfo  ## place where symbol was defined (for messages)
+    anchor: string  ## e.g. HTML anchor
+    name: string  ## short name of the symbol, not unique
+                  ## (includes backticks ` if present)
+    detailedName: string  ## longer name like `proc search(x: int): int`
   ModSection = object  ## Section like Procs, Types, etc.
-    secItems: seq[Item]  ## Pre-processed items.
+    secItems: Table[string, seq[Item]]
+                         ## Map basic name -> pre-processed items.
     finalMarkup: string  ## The items, after RST pass 2 and rendering.
   ModSections = array[TSymKind, ModSection]
   TocItem = object  ## HTML TOC item
@@ -91,12 +97,22 @@ type
     thisDir*: AbsoluteDir
     exampleGroups: OrderedTable[string, ExampleGroup]
     wroteSupportFiles*: bool
+    nimToRstFid: Table[lineinfos.FileIndex, rstast.FileIndex]
+      ## map Nim FileIndex -> RST one, it's needed because we keep them separate
 
   PDoc* = ref TDocumentor ## Alias to type less.
 
 proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
 proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
 
+proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
+  let invalid = rstast.FileIndex(-1)
+  result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
+  if result == invalid:
+    let fname = toFullPath(d.conf, info)
+    result = addFilename(d.sharedState, fname)
+    d.nimToRstFid[info.fileIndex] = result
+
 proc cmpDecimalsIgnoreCase(a, b: string): int =
   ## For sorting with correct handling of cases like 'uint8' and 'uint16'.
   ## Also handles leading zeros well (however note that leading zeros are
@@ -223,6 +239,7 @@ template declareClosures =
     of meFootnoteMismatch: k = errRstFootnoteMismatch
     of mwRedefinitionOfLabel: k = warnRstRedefinitionOfLabel
     of mwUnknownSubstitution: k = warnRstUnknownSubstitutionX
+    of mwAmbiguousLink: k = warnRstAmbiguousLink
     of mwBrokenLink: k = warnRstBrokenLink
     of mwUnsupportedLanguage: k = warnRstLanguageXNotSupported
     of mwUnsupportedField: k = warnRstFieldXNotSupported
@@ -236,7 +253,7 @@ template declareClosures =
       result = getCurrentDir() / s
       if not fileExists(result): result = ""
 
-proc parseRst(text, filename: string,
+proc parseRst(text: string,
               line, column: int,
               conf: ConfigRef, sharedState: PRstSharedState): PRstNode =
   declareClosures()
@@ -352,7 +369,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
 
 proc genComment(d: PDoc, n: PNode): PRstNode =
   if n.comment.len > 0:
-    result = parseRst(n.comment, toFullPath(d.conf, n.info),
+    d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
+    result = parseRst(n.comment,
                       toLinenumber(n.info),
                       toColumn(n.info) + DocColOffset,
                       d.conf, d.sharedState)
@@ -885,6 +903,57 @@ proc genSeeSrc(d: PDoc, path: string, line: int): string =
           "path", path.string, "line", $line, "url", gitUrl,
           "commit", commit, "devel", develBranch]])
 
+proc symbolPriority(k: TSymKind): int =
+  result = case k
+    of skMacro: -3
+    of skTemplate: -2
+    of skIterator: -1
+    else: 0  # including skProc which have higher priority
+    # documentation itself has even higher priority 1
+
+proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
+  ## Converts symbol info (names/types/parameters) in `n` into format
+  ## `LangSymbol` convenient for ``rst.nim``/``dochelpers.nim``.
+  result.name = baseName.nimIdentNormalize
+  result.symKind = k.toHumanStr
+  if k in routineKinds:
+    var
+      paramTypes: seq[string]
+    renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
+    let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
+    # In some rare cases (system.typeof) parameter type is not set for default:
+    doAssert paramTypes.len <= paramNames.len
+    for i in 0 ..< paramNames.len:
+      if i < paramTypes.len:
+        result.parameters.add (paramNames[i], paramTypes[i])
+      else:
+        result.parameters.add (paramNames[i], "")
+    result.parametersProvided = true
+
+    result.outType = renderOutType(n[paramsPos], toNormalize=true)
+
+  if k in {skProc, skFunc, skType, skIterator}:
+    # Obtain `result.generics`
+    # Use `n[miscPos]` since n[genericParamsPos] does not contain constraints
+    var genNode: PNode = nil
+    if k == skType:
+      genNode = n[1]  # FIXME: what is index 1?
+    else:
+      if n[miscPos].kind != nkEmpty:
+        genNode = n[miscPos][1]   # FIXME: what is index 1?
+    if genNode != nil:
+      var literal = ""
+      var r: TSrcGen
+      initTokRender(r, genNode, {renderNoBody, renderNoComments,
+        renderNoPragmas, renderNoProcDefs})
+      var kind = tkEof
+      while true:
+        getNextTok(r, kind, literal)
+        if kind == tkEof:
+          break
+        if kind != tkSpaces:
+          result.generics.add(literal.nimIdentNormalize)
+
 proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
   if (docFlags != kForceExport) and not isVisible(d, nameNode): return
   let
@@ -915,6 +984,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
   inc(d.id)
   let
     plainNameEsc = esc(d.target, plainName.strip)
+    detailedName = k.toHumanStr & " " & (
+        if k in routineKinds: plainName else: name)
     uniqueName = if k in routineKinds: plainNameEsc else: name
     sortName = if k in routineKinds: plainName.strip else: name
     cleanPlainSymbol = renderPlainSymbolName(nameNode)
@@ -923,20 +994,32 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags) =
     symbolOrId = d.newUniquePlainSymbol(complexSymbol)
     symbolOrIdEnc = encodeUrl(symbolOrId, usePlus = false)
     deprecationMsg = genDeprecationMsg(d, pragmaNode)
+    rstLangSymbol = toLangSymbol(k, n, cleanPlainSymbol)
+
+  # we generate anchors automatically for subsequent use in doc comments
+  let lineinfo = rstast.TLineInfo(
+      line: nameNode.info.line, col: nameNode.info.col,
+      fileIndex: addRstFileIndex(d, nameNode.info))
+  addAnchorNim(d.sharedState, refn = symbolOrId, tooltip = detailedName,
+               rstLangSymbol, priority = symbolPriority(k), info = lineinfo)
 
   nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments,
     renderDocComments, renderSyms}, symbolOrIdEnc)
 
   let seeSrc = genSeeSrc(d, toFullPath(d.conf, n.info), n.info.line.int)
 
-  d.section[k].secItems.add Item(
+  d.section[k].secItems.mgetOrPut(cleanPlainSymbol, newSeq[Item]()).add Item(
     descRst: comm,
     sortName: sortName,
+    info: lineinfo,
+    anchor: symbolOrId,
+    detailedName: detailedName,
+    name: name,
     substitutions: @[
-     "name", name, "uniqueName", uniqueName,
+     "uniqueName", uniqueName,
      "header", result, "itemID", $d.id,
      "header_plain", plainNameEsc, "itemSym", cleanPlainSymbol,
-     "itemSymOrID", symbolOrId, "itemSymEnc", plainSymbolEnc,
+     "itemSymEnc", plainSymbolEnc,
      "itemSymOrIDEnc", symbolOrIdEnc, "seeSrc", seeSrc,
      "deprecationMsg", deprecationMsg])
 
@@ -1184,6 +1267,11 @@ proc generateDoc*(d: PDoc, n, orig: PNode, docFlags: DocFlags = kDefault) =
     if comm.len != 0: d.modDescPre.add(comm)
   else: discard
 
+proc overloadGroupName(s: string, k: TSymKind): string =
+  ## Turns a name like `f` into anchor `f-procs-all`
+  #s & " " & k.toHumanStr & "s all"
+  s & "-" & k.toHumanStr & "s-all"
+
 proc finishGenerateDoc*(d: var PDoc) =
   ## Perform 2nd RST pass for resolution of links/footnotes/headings...
   # copy file map `filenames` to ``rstgen.nim`` for its warnings
@@ -1197,6 +1285,21 @@ proc finishGenerateDoc*(d: var PDoc) =
       break
   preparePass2(d.sharedState, firstRst)
 
+  # add anchors to overload groups before RST resolution
+  for k in TSymKind:
+    if k in routineKinds:
+      for plainName, overloadChoices in d.section[k].secItems:
+        if overloadChoices.len > 1:
+          let refn = overloadGroupName(plainName, k)
+          let tooltip = "$1 ($2 overloads)" % [
+                      k.toHumanStr & " " & plainName, $overloadChoices.len]
+          addAnchorNim(d.sharedState, refn, tooltip,
+                       LangSymbol(symKind: k.toHumanStr, name: plainName,
+                                  isGroup: true),
+                       priority = symbolPriority(k),
+                       # select index `0` just to have any meaningful warning:
+                       info = overloadChoices[0].info)
+
   # Finalize fragments of ``.nim`` or ``.rst`` file
   proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) =
     for f in fragments:
@@ -1207,14 +1310,33 @@ proc finishGenerateDoc*(d: var PDoc) =
       of false: result &= f.str
   proc cmp(x, y: Item): int = cmpDecimalsIgnoreCase(x.sortName, y.sortName)
   for k in TSymKind:
-    for item in d.section[k].secItems.sorted(cmp):
-      var itemDesc: string
-      renderItemPre(d, item.descRst, itemDesc)
-      d.section[k].finalMarkup.add(
-        getConfigVar(d.conf, "doc.item") % (
-            item.substitutions & @["desc", itemDesc]))
-      itemDesc = ""
-    d.section[k].secItems.setLen 0
+    # add symbols to section for each `k`, while optionally wrapping
+    # overloadable items with the same basic name by ``doc.item2``
+    let overloadableNames = toSeq(keys(d.section[k].secItems))
+    for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
+      var overloadChoices = d.section[k].secItems[plainName]
+      overloadChoices.sort(cmp)
+      var nameContent = ""
+      for item in overloadChoices:
+        var itemDesc: string
+        renderItemPre(d, item.descRst, itemDesc)
+        nameContent.add(
+          getConfigVar(d.conf, "doc.item") % (
+              item.substitutions & @[
+                "desc", itemDesc,
+                "name", item.name,
+                "itemSymOrID", item.anchor]))
+      if k in routineKinds:
+        let plainNameEsc1 = esc(d.target, plainName.strip)
+        let plainNameEsc2 = esc(d.target, plainName.strip, escMode=emUrl)
+        d.section[k].finalMarkup.add(
+          getConfigVar(d.conf, "doc.item2") % (
+            @["header_plain", plainNameEsc1,
+              "overloadGroupName", overloadGroupName(plainNameEsc2, k),
+              "content", nameContent]))
+      else:
+        d.section[k].finalMarkup.add(nameContent)
+    d.section[k].secItems.clear
   renderItemPre(d, d.modDescPre, d.modDescFinal)
   d.modDescPre.setLen 0
   d.hasToc = d.hasToc or d.sharedState.hasToc
@@ -1493,7 +1615,7 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
                    filename: AbsoluteFile, outExt: string) =
   var filen = addFileExt(filename, "txt")
   var d = newDocumentor(filen, cache, conf, outExt, isPureRst = true)
-  let rst = parseRst(readFile(filen.string), filen.string,
+  let rst = parseRst(readFile(filen.string),
                      line=LineRstInit, column=ColRstInit,
                      conf, d.sharedState)
   d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index 8bd5a0890..e13387be6 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -50,6 +50,7 @@ type
     warnSmallLshouldNotBeUsed = "SmallLshouldNotBeUsed", warnUnknownMagic = "UnknownMagic",
     warnRstRedefinitionOfLabel = "RedefinitionOfLabel",
     warnRstUnknownSubstitutionX = "UnknownSubstitutionX",
+    warnRstAmbiguousLink = "AmbiguousLink",
     warnRstBrokenLink = "BrokenLink",
     warnRstLanguageXNotSupported = "LanguageXNotSupported",
     warnRstFieldXNotSupported = "FieldXNotSupported",
@@ -123,6 +124,7 @@ const
     warnUnknownMagic: "unknown magic '$1' might crash the compiler",
     warnRstRedefinitionOfLabel: "redefinition of label '$1'",
     warnRstUnknownSubstitutionX: "unknown substitution '$1'",
+    warnRstAmbiguousLink: "ambiguous doc link $1",
     warnRstBrokenLink: "broken link '$1'",
     warnRstLanguageXNotSupported: "language '$1' not supported",
     warnRstFieldXNotSupported: "field '$1' not supported",
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
index 0da05d70d..c81ff283e 100644
--- a/compiler/typesrenderer.nim
+++ b/compiler/typesrenderer.nim
@@ -11,6 +11,12 @@ import renderer, strutils, ast, types
 
 const defaultParamSeparator* = ","
 
+template mayNormalize(s: string): string =
+  if toNormalize:
+    s.nimIdentNormalize
+  else:
+    s
+
 proc renderPlainSymbolName*(n: PNode): string =
   ## Returns the first non '*' nkIdent node from the tree.
   ##
@@ -30,24 +36,26 @@ proc renderPlainSymbolName*(n: PNode): string =
     result = ""
     #internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
 
-proc renderType(n: PNode): string =
+proc renderType(n: PNode, toNormalize: bool): string =
   ## Returns a string with the node type or the empty string.
+  ## This proc should be kept in sync with `toLangSymbols` from
+  ## ``lib/packages/docutils/dochelpers.nim``.
   case n.kind:
-  of nkIdent: result = n.ident.s
-  of nkSym: result = typeToString(n.sym.typ)
+  of nkIdent: result = mayNormalize(n.ident.s)
+  of nkSym: result = mayNormalize(typeToString(n.sym.typ))
   of nkVarTy:
     if n.len == 1:
-      result = renderType(n[0])
+      result = renderType(n[0], toNormalize)
     else:
       result = "var"
   of nkRefTy:
     if n.len == 1:
-      result = "ref." & renderType(n[0])
+      result = "ref." & renderType(n[0], toNormalize)
     else:
       result = "ref"
   of nkPtrTy:
     if n.len == 1:
-      result = "ptr." & renderType(n[0])
+      result = "ptr." & renderType(n[0], toNormalize)
     else:
       result = "ptr"
   of nkProcTy:
@@ -57,36 +65,53 @@ proc renderType(n: PNode): string =
       assert params.kind == nkFormalParams
       assert params.len > 0
       result = "proc("
-      for i in 1..<params.len: result.add(renderType(params[i]) & ',')
+      for i in 1..<params.len: result.add(renderType(params[i], toNormalize) & ',')
       result[^1] = ')'
     else:
       result = "proc"
   of nkIdentDefs:
     assert n.len >= 3
     let typePos = n.len - 2
-    let typeStr = renderType(n[typePos])
+    let typeStr = renderType(n[typePos], toNormalize)
     result = typeStr
     for i in 1..<typePos:
       assert n[i].kind in {nkSym, nkIdent}
       result.add(',' & typeStr)
   of nkTupleTy:
     result = "tuple["
-    for i in 0..<n.len: result.add(renderType(n[i]) & ',')
+    for i in 0..<n.len: result.add(renderType(n[i], toNormalize) & ',')
     result[^1] = ']'
   of nkBracketExpr:
     assert n.len >= 2
-    result = renderType(n[0]) & '['
-    for i in 1..<n.len: result.add(renderType(n[i]) & ',')
+    result = renderType(n[0], toNormalize) & '['
+    for i in 1..<n.len: result.add(renderType(n[i], toNormalize) & ',')
     result[^1] = ']'
   of nkCommand:
-    result = renderType(n[0])
+    result = renderType(n[0], toNormalize)
     for i in 1..<n.len:
       if i > 1: result.add ", "
-      result.add(renderType(n[i]))
+      result.add(renderType(n[i], toNormalize))
   else: result = ""
 
 
-proc renderParamTypes(found: var seq[string], n: PNode) =
+proc renderParamNames*(n: PNode, toNormalize=false): seq[string] =
+  ## Returns parameter names of routine `n`.
+  doAssert n.kind == nkFormalParams
+  case n.kind
+  of nkFormalParams:
+    for i in 1..<n.len:
+      if n[i].kind == nkIdentDefs:
+        # These are parameter names + type + default value node.
+        let typePos = n[i].len - 2
+        for j in 0..<typePos:
+          result.add mayNormalize($n[i][j])
+      else:  # error
+        result.add($n[i])
+  else:  #error
+    result.add $n
+
+
+proc renderParamTypes*(found: var seq[string], n: PNode, toNormalize=false) =
   ## Recursive helper, adds to `found` any types, or keeps diving the AST.
   ##
   ## The normal `doc` generator doesn't include .typ information, so the
@@ -94,12 +119,12 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
   ## generator does include the information.
   case n.kind
   of nkFormalParams:
-    for i in 1..<n.len: renderParamTypes(found, n[i])
+    for i in 1..<n.len: renderParamTypes(found, n[i], toNormalize)
   of nkIdentDefs:
     # These are parameter names + type + default value node.
     let typePos = n.len - 2
     assert typePos > 0
-    var typeStr = renderType(n[typePos])
+    var typeStr = renderType(n[typePos], toNormalize)
     if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
       # Try with the last node, maybe its a default value.
       let typ = n[typePos+1].typ
@@ -111,7 +136,8 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
     found.add($n)
     #internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
 
-proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string =
+proc renderParamTypes*(n: PNode, sep = defaultParamSeparator,
+                       toNormalize=false): string =
   ## Returns the types contained in `n` joined by `sep`.
   ##
   ## This proc expects to be passed as `n` the parameters of any callable. The
@@ -120,6 +146,10 @@ proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string =
   ## other characters may appear too, like ``[]`` or ``|``.
   result = ""
   var found: seq[string] = @[]
-  renderParamTypes(found, n)
+  renderParamTypes(found, n, toNormalize)
   if found.len > 0:
     result = found.join(sep)
+
+proc renderOutType*(n: PNode, toNormalize=false): string =
+  assert n.kind == nkFormalParams
+  result = renderType(n[0], toNormalize)
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index 162b2b4a3..c1074f344 100644
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -56,6 +56,17 @@ $seeSrc
 </div>
 """
 
+# A wrapper of a few overloaded `doc.item`s with the same basic name
+# * $header_plain - see above
+# * $overloadGroupName - the anchor for this whole group
+# * $content - string containing `doc.item`s themselves
+doc.item2 = """
+
+<div id="$overloadGroupName">
+$content
+</div>
+"""
+
 # Chunk of HTML emitted for each entry in the HTML table of contents.
 # See doc.item for available substitution variables.
 
diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg
index 4aff9b379..d7ab652eb 100644
--- a/config/nimdoc.tex.cfg
+++ b/config/nimdoc.tex.cfg
@@ -19,7 +19,8 @@ doc.section.toc = ""
 doc.item = """
 
 \vspace{1em}
-\phantomsection\addcontentsline{toc}{subsection}{$uniqueName}
+\phantomsection\addcontentsline{toc}{subsubsection}{$uniqueName}
+\label{$itemSymOrID}\hypertarget{$itemSymOrID}{}
 
 \begin{rstdocitem}
 $header
@@ -30,6 +31,13 @@ $desc
 \end{addmargin}
 """
 
+doc.item2 = """
+\phantomsection\addcontentsline{toc}{subsection}{$header_plain}
+\label{$overloadGroupName}\hypertarget{$overloadGroupName}{}
+
+$content
+"""
+
 doc.item.toc = ""
 
 doc.toc = r"\tableofcontents \newpage"
diff --git a/doc/docgen.rst b/doc/docgen.rst
index 2074ee06f..51e7102eb 100644
--- a/doc/docgen.rst
+++ b/doc/docgen.rst
@@ -229,6 +229,176 @@ Output::
 Note that the `jsondoc`:option: command outputs its JSON without pretty-printing it,
 while `jsondoc0`:option: outputs pretty-printed JSON.
 
+
+Referencing Nim symbols: simple documentation links
+===================================================
+
+You can reference Nim identifiers from Nim documentation comments, currently
+only inside their ``.nim`` file (or inside a ``.rst`` file included from
+a ``.nim``). The point is that such links will be resolved automatically
+by `nim doc`:cmd: (or `nim jsondoc`:cmd: or `nim doc2tex`:cmd:).
+This pertains to any exported symbol like `proc`, `const`, `iterator`, etc.
+Syntax for referencing is basically a normal RST one: addition of
+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.
+
+.. [*] anchors' format is described in `HTML anchor generation`_ section below.
+
+If you have a constant:
+
+.. code:: Nim
+
+   const pi* = 3.14
+
+then it should be referenced in one of the 2 forms:
+
+A. non-qualified (no symbol kind specification)::
+     pi_
+B. qualified (with symbol kind specification)::
+     `const pi`_
+
+For routine kinds there are more options. Consider this definition:
+
+.. code:: Nim
+
+   proc foo*(a: int, b: float): string
+
+Generally following syntax is allowed for referencing `foo`:
+
+*  short (without parameters):
+
+   A. non-qualified::
+
+        foo_
+
+   B. qualified::
+
+        `proc foo`_
+
+*  longer variants (with parameters):
+
+   A. non-qualified:
+
+      1) specifying parameters names::
+
+          `foo(a, b)`_
+
+      2) specifying parameters types::
+
+          `foo(int, float)`_
+
+      3) specifying both names and types::
+
+          `foo(a: int, b: float)`_
+
+      4) output parameter can also be specified if you wish::
+
+          `foo(a: int, b: float): string`_
+
+   B. qualified: all 4 options above are valid.
+      Particularly you can use the full format::
+
+        `proc foo(a: int, b: float): string`_
+
+.. Tip:: Avoid cluttering your text with extraneous information by using
+   one of shorter forms::
+
+     binarySearch_
+     `binarySearch(a, key, cmp)`_
+
+   Brevity is better for reading! If you use a short form and have an
+   ambiguity problem (see below) then just add some additional info.
+
+Symbol kind like `proc` can also be specified in the postfix form::
+
+  `foo proc`_
+  `walkDir(d: string) iterator`_
+
+.. Warning:: An ambiguity in resolving documentation links may arise because of:
+
+   1. clash with other RST anchors
+      * manually setup anchors
+      * automatically set up, e.g. section names
+   2. collision with other Nim symbols:
+
+      * routines with different parameters can exist e.g. for
+        `proc` and `template`. In this case they are split between their
+        corresponding sections in output file. Qualified references are
+        useful in this case -- just disambiguate by referring to these
+        sections explicitly::
+
+          See `foo proc`_ and `foo template`_.
+
+      * because in Nim `proc` and `iterator` belong to different namespaces,
+        so there can be a collision even if parameters are the same.
+        Use `\`proc foo\`_`:literal: or `\`iterator foo\`_`:literal: then.
+
+   Any ambiguity is always reported with Nim compiler warnings and an anchor
+   with higher priority is selected. Manual anchors have highest
+   priority, then go automatic RST anchors; then Nim-generated anchors
+   (while procs have higher priority than other Nim symbol kinds).
+
+Generic parameters can also be used. All in all, this long form will be
+recognized fine::
+
+  `proc binarySearch*[T; K](a: openArray[T], key: K, cmp: proc(T, K)): int`_
+
+**Limitations**:
+
+1. The parameters of a nested routine type can be specified only with types
+   (without parameter names, see form A.2 above).
+   E.g. for this signature:
+
+   .. code:: Nim
+
+      proc binarySearch*[T, K](a: openArray[T]; key: K;
+                               cmp: proc (x: T; y: K): int {.closure.}): int
+                                          ~~    ~~   ~~~~~
+
+   you cannot use names underlined by `~~` so it must be referenced with
+   ``cmp: proc(T, K)``. Hence these forms are valid::
+
+     `binarySearch(a: openArray[T], key: K, cmp: proc(T, K))`_
+     `binarySearch(openArray[T], K, proc(T, K))`_
+     `binarySearch(a, key, cmp)`_
+2. Default values in routine parameters are not recognized, one needs to
+   specify the type and/or name instead. E.g. for referencing `proc f(x = 7)`
+   use one of the mentioned forms::
+
+     `f(int)`_ or `f(x)`_ or `f(x: int)`_.
+3. Generic parameters must be given the same way as in the
+   definition of referenced symbol.
+
+   * their names should be the same
+   * parameters list should be given the same way, e.g. without substitutions
+     between commas (,) and semicolons (;).
+
+.. Note:: A bit special case is operators
+   (as their signature is also defined with `\``):
+
+   .. code:: Nim
+
+      func `$`(x: MyType): string
+      func `[]`*[T](x: openArray[T]): T
+
+   A short form works without additional backticks::
+
+     `$`_
+     `[]`_
+
+   However for fully-qualified reference copy-pasting backticks (`) into other
+   backticks will not work in our RST parser (because we use Markdown-like
+   inline markup rules). You need either to delete backticks or keep
+   them and escape with backslash \\::
+
+      no backticks: `func $`_
+      escaped:  `func \`$\``_
+      no backticks: `func [][T](x: openArray[T]): T`_
+      escaped:  `func \`[]\`[T](x: openArray[T]): T`_
+
 Related Options
 ===============
 
diff --git a/doc/nimdoc.css b/doc/nimdoc.css
index 3353f1cda..7c819ea30 100644
--- a/doc/nimdoc.css
+++ b/doc/nimdoc.css
@@ -263,6 +263,10 @@ a.reference-toplevel {
   font-weight: bold;

 }

 

+a.nimdoc {

+  word-spacing: 0.3em;

+}

+

 a.toc-backref {

   text-decoration: none;

   color: var(--text); }

diff --git a/lib/packages/docutils/dochelpers.nim b/lib/packages/docutils/dochelpers.nim
new file mode 100644
index 000000000..c488c4d99
--- /dev/null
+++ b/lib/packages/docutils/dochelpers.nim
@@ -0,0 +1,267 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2021 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Integration helpers between ``docgen.nim`` and ``rst.nim``.
+##
+## Function `toLangSymbol(linkText)`_ produces a signature `docLink` of
+## `type LangSymbol`_ in ``rst.nim``, while `match(generated, docLink)`_
+## matches it with `generated`, produced from `PNode` by ``docgen.rst``.
+
+import rstast
+
+type
+  LangSymbol* = object       ## symbol signature in Nim
+    symKind*: string           ## "proc", "const", etc
+    name*: string              ## plain symbol name without any parameters
+    generics*: string          ## generic parameters (without brackets)
+    isGroup*: bool             ## is LangSymbol a group with overloads?
+    # the following fields are valid iff `isGroup` == false
+    # (always false when parsed by `toLangSymbol` because link like foo_
+    # can point to just a single symbol foo, e.g. proc).
+    parametersProvided*: bool  ## to disambiguate `proc f`_ and `proc f()`_
+    parameters*: seq[tuple[name: string, `type`: string]]
+                               ## name-type seq, e.g. for proc
+    outType*: string           ## result type, e.g. for proc
+
+func nimIdentBackticksNormalize*(s: string): string =
+  ## Normalizes the string `s` as a Nim identifier.
+  ##
+  ## Unlike `nimIdentNormalize` removes spaces and backticks.
+  ##
+  ## .. Warning:: No checking (e.g. that identifiers cannot start from
+  ##    digits or '_', or that number of backticks is even) is performed.
+  runnableExamples:
+    doAssert nimIdentBackticksNormalize("Foo_bar") == "Foobar"
+    doAssert nimIdentBackticksNormalize("FoO BAr") == "Foobar"
+    doAssert nimIdentBackticksNormalize("`Foo BAR`") == "Foobar"
+    doAssert nimIdentBackticksNormalize("` Foo BAR `") == "Foobar"
+    # not a valid identifier:
+    doAssert nimIdentBackticksNormalize("`_x_y`") == "_xy"
+  result = newString(s.len)
+  var firstChar = true
+  var j = 0
+  for i in 0..len(s) - 1:
+    if s[i] in {'A'..'Z'}:
+      if not firstChar:  # to lowercase
+        result[j] = chr(ord(s[i]) + (ord('a') - ord('A')))
+      else:
+        result[j] = s[i]
+        firstChar = false
+      inc j
+    elif s[i] notin {'_', ' ', '`'}:
+      result[j] = s[i]
+      inc j
+      firstChar = false
+    elif s[i] == '_' and firstChar:
+      result[j] = '_'
+      inc j
+      firstChar = false
+    else: discard  # just omit '`' or ' '
+  if j != s.len: setLen(result, j)
+
+proc toLangSymbol*(linkText: PRstNode): LangSymbol =
+  ## Parses `linkText` into a more structured form using a state machine.
+  ##
+  ## This proc is designed to allow link syntax with operators even
+  ## without escaped backticks inside::
+  ##   
+  ##   `proc *`_
+  ##   `proc []`_
+  ##
+  ## This proc should be kept in sync with the `renderTypes` proc from
+  ## ``compiler/typesrenderer.nim``.
+  assert linkText.kind in {rnRef, rnInner}
+
+  const NimDefs = ["proc", "func", "macro", "method", "iterator",
+                   "template", "converter", "const", "type", "var"]
+  type
+    State = enum
+      inBeginning
+      afterSymKind
+      beforeSymbolName  # auxiliary state to catch situations like `proc []`_ after space
+      atSymbolName
+      afterSymbolName
+      genericsPar
+      parameterName
+      parameterType
+      outType
+  var state = inBeginning
+  var curIdent = ""
+  template flushIdent() =
+    if curIdent != "":
+      case state
+      of inBeginning:  doAssert false, "incorrect state inBeginning"
+      of afterSymKind:  result.symKind = curIdent
+      of beforeSymbolName:  doAssert false, "incorrect state beforeSymbolName"
+      of atSymbolName: result.name = curIdent.nimIdentBackticksNormalize
+      of afterSymbolName: doAssert false, "incorrect state afterSymbolName"
+      of genericsPar: result.generics = curIdent
+      of parameterName: result.parameters.add (curIdent, "")
+      of parameterType:
+        for a in countdown(result.parameters.len - 1, 0):
+          if result.parameters[a].`type` == "":
+            result.parameters[a].`type` = curIdent
+      of outType: result.outType = curIdent
+      curIdent = ""
+  var parens = 0
+  let L = linkText.sons.len
+  template s(i: int): string = linkText.sons[i].text
+  var i = 0
+  template nextState =
+    case s(i)
+    of " ":
+      if state == afterSymKind:
+        flushIdent
+        state = beforeSymbolName
+    of "`":
+      curIdent.add "`"
+      inc i
+      while i < L:  # add contents between ` ` as a whole
+        curIdent.add s(i)
+        if s(i) == "`":
+          break
+        inc i
+      curIdent = curIdent.nimIdentBackticksNormalize
+      if state in {inBeginning, afterSymKind, beforeSymbolName}:
+        state = atSymbolName
+        flushIdent
+        state = afterSymbolName
+    of "[":
+      if state notin {inBeginning, afterSymKind, beforeSymbolName}:
+        inc parens
+      if state in {inBeginning, afterSymKind, beforeSymbolName}:
+        state = atSymbolName
+        curIdent.add s(i)
+      elif state in {atSymbolName, afterSymbolName} and parens == 1:
+        flushIdent
+        state = genericsPar
+        curIdent.add s(i)
+      else: curIdent.add s(i)
+    of "]":
+      if state notin {inBeginning, afterSymKind, beforeSymbolName, atSymbolName}:
+        dec parens
+      if state == genericsPar and parens == 0:
+        curIdent.add s(i)
+        flushIdent
+      else: curIdent.add s(i)
+    of "(":
+      inc parens
+      if state in {inBeginning, afterSymKind, beforeSymbolName}:
+        result.parametersProvided = true
+        state = atSymbolName
+        flushIdent
+        state = parameterName
+      elif state in {atSymbolName, afterSymbolName, genericsPar} and parens == 1:
+        result.parametersProvided = true
+        flushIdent
+        state = parameterName
+      else: curIdent.add s(i)
+    of ")":
+      dec parens
+      if state in {parameterName, parameterType} and parens == 0:
+        flushIdent
+        state = outType
+      else: curIdent.add s(i)
+    of "{":  # remove pragmas
+      while i < L:
+        if s(i) == "}":
+          break
+        inc i
+    of ",", ";":
+      if state in {parameterName, parameterType} and parens == 1:
+        flushIdent
+        state = parameterName
+      else: curIdent.add s(i)
+    of "*":  # skip export symbol
+      if state == atSymbolName:
+        flushIdent
+        state = afterSymbolName
+      elif state == afterSymbolName:
+        discard
+      else: curIdent.add "*"
+    of ":":
+      if state == outType: discard
+      elif state == parameterName:
+        flushIdent
+        state = parameterType
+      else: curIdent.add ":"
+    else:
+      let isPostfixSymKind = i > 0 and i == L - 1 and
+          result.symKind == "" and s(i) in NimDefs
+      if isPostfixSymKind:  # for links like `foo proc`_
+        result.symKind = s(i)
+      else:
+        case state
+        of inBeginning:
+          if s(i) in NimDefs:
+            state = afterSymKind
+          else:
+            state = atSymbolName
+          curIdent.add s(i)
+        of afterSymKind, beforeSymbolName:
+          state = atSymbolName
+          curIdent.add s(i)
+        of parameterType:
+          case s(i)
+          of "ref": curIdent.add "ref."
+          of "ptr": curIdent.add "ptr."
+          of "var": discard
+          else: curIdent.add s(i).nimIdentBackticksNormalize
+        of atSymbolName:
+          curIdent.add s(i)
+        else:
+          curIdent.add s(i).nimIdentBackticksNormalize
+  while i < L:
+    nextState
+    inc i
+  if state == afterSymKind:  # treat `type`_ as link to symbol `type`
+    state = atSymbolName
+  flushIdent
+  result.isGroup = false
+
+proc match*(generated: LangSymbol, docLink: LangSymbol): bool =
+  ## Returns true if `generated` can be a target for `docLink`.
+  ## If `generated` is an overload group then only `symKind` and `name`
+  ## are compared for success.
+  result = true
+  if docLink.symKind != "":
+    if generated.symKind == "proc":
+      result = docLink.symKind in ["proc", "func"]
+    else:
+      result = generated.symKind == docLink.symKind
+    if not result: return
+  result = generated.name == docLink.name
+  if not result: return
+  if generated.isGroup:
+    # if `()` were added then it's not a reference to the whole group:
+    return not docLink.parametersProvided
+  if docLink.generics != "":
+    result = generated.generics == docLink.generics
+    if not result: return
+  if docLink.outType != "":
+    result = generated.outType == docLink.outType
+    if not result: return
+  if docLink.parametersProvided:
+    result = generated.parameters.len == docLink.parameters.len
+    if not result: return
+    var onlyType = false
+    for i in 0 ..< generated.parameters.len:
+      let g = generated.parameters[i]
+      let d = docLink.parameters[i]
+      if i == 0:
+        if g.`type` == d.name:
+          onlyType = true  # only types, not names, are provided in `docLink`
+      if onlyType:
+        result = g.`type` == d.name:
+      else:
+        if d.`type` != "":
+          result = g.`type` == d.`type`
+          if not result: return
+        result = g.name == d.name
+      if not result: return
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 29234f28b..2e908f4e5 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -114,7 +114,7 @@
 ## .. _`extra features`:
 ##
 ## Optional additional features, turned on by ``options: RstParseOption`` in
-## `rstParse proc <#rstParse,string,string,int,int,bool,RstParseOptions,FindFileHandler,MsgHandler>`_:
+## `proc rstParse`_:
 ##
 ## * emoji / smiley symbols
 ## * Markdown tables
@@ -196,7 +196,7 @@
 ## .. _Sphinx roles: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html
 
 import
-  os, strutils, rstast, std/enumutils, algorithm, lists, sequtils,
+  os, strutils, rstast, dochelpers, std/enumutils, algorithm, lists, sequtils,
   std/private/miscdollars, tables
 from highlite import SourceLanguage, getSourceLanguage
 
@@ -231,6 +231,7 @@ type
     meFootnoteMismatch = "mismatch in number of footnotes and their refs: $1",
     mwRedefinitionOfLabel = "redefinition of label '$1'",
     mwUnknownSubstitution = "unknown substitution '$1'",
+    mwAmbiguousLink = "ambiguous doc link $1",
     mwBrokenLink = "broken link '$1'",
     mwUnsupportedLanguage = "language '$1' not supported",
     mwUnsupportedField = "field '$1' not supported",
@@ -473,12 +474,42 @@ type
     hasPeers: bool       # has headings on the same level of hierarchy?
   LevelMap = seq[LevelInfo]   # Saves for each possible title adornment
                               # style its level in the current document.
+  SubstitutionKind = enum
+    rstSubstitution = "substitution",
+    hyperlinkAlias = "hyperlink alias",
+    implicitHyperlinkAlias = "implicitly-generated hyperlink alias"
   Substitution = object
+    kind*: SubstitutionKind
     key*: string
     value*: PRstNode
-  AnchorSubst = tuple
-    mainAnchor: string
-    aliases: seq[string]
+    info*: TLineInfo   # place where the substitution was defined
+  AnchorRule = enum
+    arInternalRst,  ## For automatically generated RST anchors (from
+                    ## headings, footnotes, inline internal targets):
+                    ## case-insensitive, 1-space-significant (by RST spec)
+    arNim   ## For anchors generated by ``docgen.rst``: Nim-style case
+            ## sensitivity, etc. (see `proc normalizeNimName`_ for details)
+    arHyperlink,  ## For links with manually set anchors in
+                  ## form `text <pagename.html#anchor>`_
+  RstAnchorKind = enum
+    manualDirectiveAnchor = "manual directive anchor",
+    manualInlineAnchor = "manual inline anchor",
+    footnoteAnchor = "footnote anchor",
+    headlineAnchor = "implicitly-generated headline anchor"
+  AnchorSubst = object
+    mainAnchor: ref string  # A reference name that will be inserted directly
+                            # into HTML/Latex. It's declared as `ref` because
+                            # it can be shared between aliases.
+    info: TLineInfo         # where the anchor was defined
+    priority: int
+    case kind: range[arInternalRst .. arNim]
+    of arInternalRst:
+      anchorType: RstAnchorKind
+    of arNim:
+      tooltip: string       # displayed tooltip for Nim-generated anchors
+      langSym: LangSymbol
+  AnchorSubstTable = Table[string, seq[AnchorSubst]]
+                         # use `seq` to account for duplicate anchors
   FootnoteType = enum
     fnManualNumber,     # manually numbered footnote like [3]
     fnAutoNumber,       # auto-numbered footnote [#]
@@ -505,7 +536,8 @@ type
     currRoleKind: RstNodeKind   # ... and its node kind
     subs: seq[Substitution]     # substitutions
     refs*: seq[Substitution]    # references
-    anchors*: seq[AnchorSubst]  # internal target substitutions
+    anchors*: AnchorSubstTable
+                                # internal target substitutions
     lineFootnoteNum: seq[TLineInfo]     # footnote line, auto numbers .. [#]
     lineFootnoteNumRef: seq[TLineInfo]  # footnote line, their reference [#]_
     currFootnoteNumRef: int             # ... their counter for `resolveSubs`
@@ -518,7 +550,7 @@ type
     findFile: FindFileHandler   # How to find files.
     filenames*: RstFileTable    # map file name <-> FileIndex (for storing
                                 # file names for warnings after 1st stage)
-    currFileIdx: FileIndex      # current index in `filesnames`
+    currFileIdx*: FileIndex     # current index in `filenames`
     hasToc*: bool
 
   PRstSharedState* = ref RstSharedState
@@ -532,6 +564,7 @@ type
                                 ## in case of error/warning reporting to
                                 ## (relative) line/column of the token.
     curAnchor*: string          # variable to track latest anchor in s.anchors
+    curAnchorName*: string      # corresponding name in human-readable format
 
   EParseError* = object of ValueError
 
@@ -590,13 +623,16 @@ proc whichRoleAux(sym: string): RstNodeKind =
 
 proc len(filenames: RstFileTable): int = filenames.idxToFilename.len
 
-proc setCurrFilename(s: PRstSharedState, file1: string) =
+proc addFilename*(s: PRstSharedState, file1: string): FileIndex =
+  ## Returns index of filename, adding it if it has not been used before
   let nextIdx = s.filenames.len.FileIndex
-  let v = getOrDefault(s.filenames.filenameToIdx, file1, default = nextIdx)
-  if v == nextIdx:
-    s.filenames.filenameToIdx[file1] = v
+  result = getOrDefault(s.filenames.filenameToIdx, file1, default = nextIdx)
+  if result == nextIdx:
+    s.filenames.filenameToIdx[file1] = result
     s.filenames.idxToFilename.add file1
-  s.currFileIdx = v
+
+proc setCurrFilename*(s: PRstSharedState, file1: string) =
+  s.currFileIdx = addFilename(s, file1)
 
 proc getFilename(filenames: RstFileTable, fid: FileIndex): string =
   doAssert(0 <= fid.int and fid.int < filenames.len,
@@ -730,6 +766,8 @@ proc initParser(p: var RstParser, sharedState: PRstSharedState) =
   p.s = sharedState
 
 proc addNodesAux(n: PRstNode, result: var string) =
+  if n == nil:
+    return
   if n.kind == rnLeaf:
     result.add(n.text)
   else:
@@ -738,6 +776,11 @@ proc addNodesAux(n: PRstNode, result: var string) =
 proc addNodes(n: PRstNode): string =
   n.addNodesAux(result)
 
+proc linkName(n: PRstNode): string =
+  ## Returns a normalized reference name, see:
+  ## https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names
+  n.addNodes.toLowerAscii
+
 proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
   template special(s) =
     if b:
@@ -804,15 +847,26 @@ proc findSub(s: PRstSharedState, n: PRstNode): int =
       return i
   result = -1
 
+proc lineInfo(p: RstParser, iTok: int): TLineInfo =
+  result.col = int16(p.col + p.tok[iTok].col)
+  result.line = uint16(p.line + p.tok[iTok].line)
+  result.fileIndex = p.s.currFileIdx
+
+proc lineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx)
+# TODO: we need this simplification because we don't preserve exact starting
+# token of currently parsed element:
+proc prevLineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx-1)
+
 proc setSub(p: var RstParser, key: string, value: PRstNode) =
   var length = p.s.subs.len
   for i in 0 ..< length:
     if key == p.s.subs[i].key:
       p.s.subs[i].value = value
       return
-  p.s.subs.add(Substitution(key: key, value: value))
+  p.s.subs.add(Substitution(key: key, value: value, info: prevLineInfo(p)))
 
-proc setRef(p: var RstParser, key: string, value: PRstNode) =
+proc setRef(p: var RstParser, key: string, value: PRstNode,
+            refType: SubstitutionKind) =
   var length = p.s.refs.len
   for i in 0 ..< length:
     if key == p.s.refs[i].key:
@@ -820,37 +874,111 @@ proc setRef(p: var RstParser, key: string, value: PRstNode) =
         rstMessage(p, mwRedefinitionOfLabel, key)
       p.s.refs[i].value = value
       return
-  p.s.refs.add(Substitution(key: key, value: value))
+  p.s.refs.add(Substitution(kind: refType, key: key, value: value,
+                            info: prevLineInfo(p)))
 
-proc findRef(s: PRstSharedState, key: string): PRstNode =
+proc findRef(s: PRstSharedState, key: string): seq[Substitution] =
   for i in countup(0, high(s.refs)):
     if key == s.refs[i].key:
-      return s.refs[i].value
-
-proc addAnchor(p: var RstParser, refn: string, reset: bool) =
-  ## add anchor `refn` to anchor aliases and update last anchor ``curAnchor``
-  if p.curAnchor == "":
-    p.s.anchors.add (refn, @[refn])
+      result.add s.refs[i]
+
+# Ambiguity in links: we don't follow procedure of removing implicit targets
+# defined in https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#implicit-hyperlink-targets
+# Instead we just give explicit links a higher priority than to implicit ones
+# and report ambiguities as warnings. Hopefully it is easy to remove
+# ambiguities manually. Nim auto-generated links from ``docgen.nim``
+# have lowest priority: 1 (for procs) and below for other symbol types.
+
+proc refPriority(k: SubstitutionKind): int =
+  case k
+  of rstSubstitution: result = 8
+  of hyperlinkAlias: result = 7
+  of implicitHyperlinkAlias: result = 2
+
+proc internalRefPriority(k: RstAnchorKind): int =
+  case k
+  of manualDirectiveAnchor: result = 6
+  of manualInlineAnchor: result = 5
+  of footnoteAnchor: result = 4
+  of headlineAnchor: result = 3
+
+proc addAnchorRst(p: var RstParser, name: string, refn: string, reset: bool,
+                  anchorType: RstAnchorKind) =
+  ## Adds anchor `refn` with an alias `name` and
+  ## updates the corresponding `curAnchor` / `curAnchorName`.
+  let prio = internalRefPriority(anchorType)
+  if p.curAnchorName == "":
+    var anchRef = new string
+    anchRef[] = refn
+    p.s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add(
+        AnchorSubst(kind: arInternalRst, mainAnchor: anchRef, priority: prio,
+                    info: prevLineInfo(p), anchorType: anchorType))
   else:
-    p.s.anchors[^1].mainAnchor = refn
-    p.s.anchors[^1].aliases.add refn
+    # override previous mainAnchor by `ref` in all aliases
+    var anchRef = p.s.anchors[p.curAnchorName][0].mainAnchor
+    anchRef[] = refn
+    p.s.anchors.mgetOrPut(name, newSeq[AnchorSubst]()).add(
+        AnchorSubst(kind: arInternalRst, mainAnchor: anchRef, priority: prio,
+                    info: prevLineInfo(p), anchorType: anchorType))
   if reset:
     p.curAnchor = ""
+    p.curAnchorName = ""
   else:
     p.curAnchor = refn
+    p.curAnchorName = name
+
+proc addAnchorNim*(s: var PRstSharedState, refn: string, tooltip: string,
+                   langSym: LangSymbol, priority: int,
+                   info: TLineInfo) =
+  ## Adds an anchor `refn` (`mainAnchor`), which follows
+  ## the rule `arNim` (i.e. a symbol in ``*.nim`` file)
+  var anchRef = new string
+  anchRef[] = refn
+  s.anchors.mgetOrPut(langSym.name, newSeq[AnchorSubst]()).add(
+      AnchorSubst(kind: arNim, mainAnchor: anchRef, langSym: langSym,
+                  tooltip: tooltip, priority: priority,
+                  info: info))
+
+proc findMainAnchorNim(s: PRstSharedState, signature: PRstNode,
+                       info: TLineInfo):
+                      seq[AnchorSubst] =
+  let langSym = toLangSymbol(signature)
+  let substitutions = s.anchors.getOrDefault(langSym.name,
+                                             newSeq[AnchorSubst]())
+  if substitutions.len == 0:
+    return
+  # map symKind (like "proc") -> found symbols/groups:
+  var found: Table[string, seq[AnchorSubst]]
+  for s in substitutions:
+    if s.kind == arNim:
+      if match(s.langSym, langSym):
+        found.mgetOrPut(s.langSym.symKind, newSeq[AnchorSubst]()).add s
+  for symKind, sList in found:
+    if sList.len == 1:
+      result.add sList[0]
+    else:  # > 1, there are overloads, potential ambiguity in this `symKind`
+      if langSym.parametersProvided:
+        # there are non-group signatures, select only them
+        for s in sList:
+          if not s.langSym.isGroup:
+            result.add s
+      else:  # when there are many overloads a link like foo_ points to all
+             # of them, so selecting the group
+        var foundGroup = true
+        for s in sList:
+          if s.langSym.isGroup:
+            result.add s
+            foundGroup = true
+            break
+        doAssert foundGroup, "docgen has not generated the group"
 
-proc findMainAnchor(s: PRstSharedState, refn: string): string =
-  for subst in s.anchors:
-    if subst.mainAnchor == refn:  # no need to rename
-      result = subst.mainAnchor
-      break
-    var toLeave = false
-    for anchor in subst.aliases:
-      if anchor == refn:  # this anchor will be named as mainAnchor
-        result = subst.mainAnchor
-        toLeave = true
-    if toLeave:
-      break
+proc findMainAnchorRst(s: PRstSharedState, linkText: string, info: TLineInfo):
+                      seq[AnchorSubst] =
+  let name = linkText.toLowerAscii
+  let substitutions = s.anchors.getOrDefault(name, newSeq[AnchorSubst]())
+  for s in substitutions:
+    if s.kind == arInternalRst:
+      result.add s
 
 proc addFootnoteNumManual(p: var RstParser, num: int) =
   ## add manually-numbered footnote
@@ -860,13 +988,6 @@ proc addFootnoteNumManual(p: var RstParser, num: int) =
       return
   p.s.footnotes.add((fnManualNumber, num, -1, -1, $num))
 
-proc lineInfo(p: RstParser, iTok: int): TLineInfo =
-  result.col = int16(p.col + p.tok[iTok].col)
-  result.line = uint16(p.line + p.tok[iTok].line)
-  result.fileIndex = p.s.currFileIdx
-
-proc lineInfo(p: RstParser): TLineInfo = lineInfo(p, p.idx)
-
 proc addFootnoteNumAuto(p: var RstParser, label: string) =
   ## add auto-numbered footnote.
   ## Empty label [#] means it'll be resolved by the occurrence.
@@ -989,6 +1110,7 @@ proc newRstNodeA(p: var RstParser, kind: RstNodeKind): PRstNode =
   if p.curAnchor != "":
     result.anchor = p.curAnchor
     p.curAnchor = ""
+    p.curAnchorName = ""
 
 template newLeaf(s: string): PRstNode = newRstLeaf(s)
 
@@ -1255,7 +1377,7 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode =
       else:
         newKind = rnHyperlink
         newSons = @[a, b]
-        setRef(p, rstnodeToRefname(a), b)
+        setRef(p, rstnodeToRefname(a), b, implicitHyperlinkAlias)
       result = newRstNode(newKind, newSons)
     else:  # some link that will be resolved in `resolveSubs`
       newKind = rnRef
@@ -1562,7 +1684,8 @@ proc parseInline(p: var RstParser, father: PRstNode) =
       inc p.idx
       parseUntil(p, n, "`", false)
       let refn = rstnodeToRefname(n)
-      p.s.anchors.add (refn, @[refn])
+      addAnchorRst(p, name = linkName(n), refn = refn, reset = true,
+                   anchorType=manualInlineAnchor)
       father.add(n)
     elif roSupportMarkdown in p.s.options and currentTok(p).symbol == "```":
       inc p.idx
@@ -2084,7 +2207,8 @@ proc parseHeadline(p: var RstParser): PRstNode =
     result.level = getLevel(p, c, hasOverline=false)
     checkHeadingHierarchy(p, result.level)
     p.s.hCurLevel = result.level
-  addAnchor(p, rstnodeToRefname(result), reset=true)
+  addAnchorRst(p, linkName(result), rstnodeToRefname(result), reset=true,
+               anchorType=headlineAnchor)
 
 proc parseOverline(p: var RstParser): PRstNode =
   var c = currentTok(p).symbol[0]
@@ -2106,7 +2230,8 @@ proc parseOverline(p: var RstParser): PRstNode =
   if currentTok(p).kind == tkAdornment:
     inc p.idx
     if currentTok(p).kind == tkIndent: inc p.idx
-  addAnchor(p, rstnodeToRefname(result), reset=true)
+  addAnchorRst(p, linkName(result), rstnodeToRefname(result), reset=true,
+               anchorType=headlineAnchor)
 
 type
   IntSeq = seq[int]
@@ -2837,7 +2962,7 @@ proc parseFootnote(p: var RstParser): PRstNode =
     anchor.add $p.s.lineFootnoteSym.len
   of fnCitation:
     anchor.add rstnodeToRefname(label)
-  addAnchor(p, anchor, reset=true)
+  addAnchorRst(p, anchor, anchor, reset=true, anchorType=footnoteAnchor)
   result.anchor = anchor
   if currentTok(p).kind == tkWhite: inc p.idx
   discard parseBlockContent(p, result, parseSectionWrapper)
@@ -2858,13 +2983,23 @@ proc parseDotDot(p: var RstParser): PRstNode =
   elif match(p, p.idx, " _"):
     # hyperlink target:
     inc p.idx, 2
-    var a = getReferenceName(p, ":")
+    var ending = ":"
+    if currentTok(p).symbol == "`":
+      inc p.idx
+      ending = "`"
+    var a = getReferenceName(p, ending)
+    if ending == "`":
+      if currentTok(p).symbol == ":":
+        inc p.idx
+      else:
+        rstMessage(p, meExpected, ":")
     if currentTok(p).kind == tkWhite: inc p.idx
     var b = untilEol(p)
     if len(b) == 0:  # set internal anchor
-      addAnchor(p, rstnodeToRefname(a), reset=false)
+      addAnchorRst(p, linkName(a), rstnodeToRefname(a), reset=false,
+                   anchorType=manualDirectiveAnchor)
     else:  # external hyperlink
-      setRef(p, rstnodeToRefname(a), b)
+      setRef(p, rstnodeToRefname(a), b, refType=hyperlinkAlias)
   elif match(p, p.idx, " |"):
     # substitution definitions:
     inc p.idx, 2
@@ -2892,7 +3027,7 @@ proc rstParsePass1*(fragment: string,
                     sharedState: PRstSharedState): PRstNode =
   ## Parses an RST `fragment`.
   ## The result should be further processed by
-  ## `preparePass2` and `resolveSubs` (which is pass 2).
+  ## preparePass2_ and resolveSubs_ (which is pass 2).
   var p: RstParser
   initParser(p, sharedState)
   p.line = line
@@ -2905,6 +3040,65 @@ proc preparePass2*(s: PRstSharedState, mainNode: PRstNode) =
   countTitles(s, mainNode)
   orderFootnotes(s)
 
+proc resolveLink(s: PRstSharedState, n: PRstNode) : PRstNode =
+    # Associate this link alias with its target and change node kind to
+    # rnHyperlink or rnInternalRef appropriately.
+    type LinkDef = object
+      ar: AnchorRule
+      priority: int
+      tooltip: string
+      target: PRstNode
+      info: TLineInfo
+    proc cmp(x, y: LinkDef): int =
+      result = cmp(x.priority, y.priority)
+      if result == 0:
+        result = cmp(x.target, y.target)
+    var foundLinks: seq[LinkDef]
+    let text = newRstNode(rnInner, n.sons)
+    let refn = rstnodeToRefname(n)
+    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)
+    for subst in substRst:
+      foundLinks.add LinkDef(ar: arInternalRst, priority: subst.priority,
+                             target: newLeaf(subst.mainAnchor[]),
+                             info: subst.info,
+                             tooltip: "(" & $subst.anchorType & ")")
+    if roNimFile in s.options:
+      let substNim = findMainAnchorNim(s, signature=text, n.info)
+      for subst in substNim:
+        foundLinks.add LinkDef(ar: arNim, priority: subst.priority,
+                               target: newLeaf(subst.mainAnchor[]),
+                               info: subst.info, tooltip: subst.tooltip)
+    foundLinks.sort(cmp = cmp, order = Descending)
+    let linkText = addNodes(n)
+    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]
+      if kind == rnNimdocRef: result.tooltip = foundLinks[0].tooltip
+      if foundLinks.len > 1:  # report ambiguous link
+        var targets = newSeq[string]()
+        for l in foundLinks:
+          var t = "    "
+          if s.filenames.len > 1:
+            t.add getFilename(s.filenames, l.info.fileIndex)
+          let n = l.info.line
+          let c = l.info.col + ColRstOffset
+          t.add "($1, $2): $3" % [$n, $c, l.tooltip]
+          targets.add t
+        rstMessage(s.filenames, s.msgHandler, n.info, mwAmbiguousLink,
+                   "`$1`\n  clash:\n$2" % [
+                     linkText, targets.join("\n")])
+    else:  # nothing found
+      result = n
+      rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, linkText)
+
 proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode =
   ## Makes pass 2 of RST parsing.
   ## Resolves substitutions and anchor aliases, groups footnotes.
@@ -2933,21 +3127,7 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode =
     elif s.hTitleCnt == 0:
       n.level += 1
   of rnRef:
-    let refn = rstnodeToRefname(n)
-    var y = findRef(s, refn)
-    if y != nil:
-      result = newRstNode(rnHyperlink)
-      let text = newRstNode(rnInner, n.sons)
-      result.sons = @[text, y]
-    else:
-      let anchor = findMainAnchor(s, refn)
-      if anchor != "":
-        result = newRstNode(rnInternalRef)
-        let text = newRstNode(rnInner, n.sons)
-        result.sons = @[text,             # visible text of reference
-                        newLeaf(anchor)]  # link itself
-      else:
-        rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn)
+    result = resolveLink(s, n)
   of rnFootnote:
     var (fnType, num) = getFootnoteType(n.sons[0])
     case fnType
@@ -2993,9 +3173,10 @@ proc resolveSubs*(s: PRstSharedState, n: PRstNode): PRstNode =
     of fnCitation:
       result.add n.sons[0]
       refn.add rstnodeToRefname(n)
-    let anch = findMainAnchor(s, refn)
-    if anch != "":
-      result.add newLeaf(anch)     # add link
+    # TODO: correctly report ambiguities
+    let anchorInfo = findMainAnchorRst(s, refn, n.info)
+    if anchorInfo.len != 0:
+      result.add newLeaf(anchorInfo[0].mainAnchor[])  # add link
     else:
       rstMessage(s.filenames, s.msgHandler, n.info, mwBrokenLink, refn)
       result.add newLeaf(refn)  # add link
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index e1ed7c099..bc7b9a650 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -43,6 +43,7 @@ type
     rnFootnoteGroup,          # footnote group - exists for a purely stylistic
                               # reason: to display a few footnotes as 1 block
     rnStandaloneHyperlink, rnHyperlink, rnRef, rnInternalRef, rnFootnoteRef,
+    rnNimdocRef,              # reference to automatically generated Nim symbol
     rnDirective,              # a general directive
     rnDirArg,                 # a directive argument (for some directives).
                               # here are directives that are not rnDirective:
@@ -104,6 +105,8 @@ type
         rnInterpretedText, rnField, rnInlineCode, rnCodeBlock, rnFootnoteRef:
       info*: TLineInfo        ## To have line/column info for warnings at
                               ## nodes that are post-processed after parsing
+    of rnNimdocRef:
+      tooltip*: string
     else:
       discard
     anchor*: string           ## anchor, internal link target
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 8eac37307..a556aa2e3 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -60,8 +60,8 @@ type
   MetaEnum* = enum
     metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
 
-  EscapeMode = enum  # in Latex text inside options [] and URLs is
-                     # escaped slightly differently than in normal text
+  EscapeMode* = enum  # in Latex text inside options [] and URLs is
+                      # escaped slightly differently than in normal text
     emText, emOption, emUrl  # emText is currently used for code also
 
   RstGenerator* = object of RootObj
@@ -201,7 +201,9 @@ proc addTexChar(dest: var string, c: char, escMode: EscapeMode) =
   ## All escapes that need to work in text and code blocks (`emText` mode)
   ## should start from \ (to be compatible with fancyvrb/fvextra).
   case c
-  of '_', '$', '&', '#', '%': add(dest, "\\" & c)
+  of '_', '&', '#', '%': add(dest, "\\" & c)
+  # commands \label and \pageref don't accept \$ by some reason but OK with $:
+  of '$': (if escMode == emUrl: add(dest, c) else: add(dest, "\\" & c))
   # \~ and \^ have a special meaning unless they are followed by {}
   of '~', '^': add(dest, "\\" & c & "{}")
   # Latex loves to substitute ` to opening quote, even in texttt mode!
@@ -1180,7 +1182,8 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) =
         "$1\n\\end{rstadmonition}\n",
       result)
 
-proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external: bool) =
+proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string,
+                     external: bool, nimdoc = false, tooltip="") =
   var linkStr = ""
   block:
     let mode = d.escMode
@@ -1189,14 +1192,19 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string, external
     d.escMode = mode
   var textStr = ""
   renderRstToOut(d, text, textStr)
+  let nimDocStr = if nimdoc: " nimdoc" else: ""
+  var tooltipStr = ""
+  if tooltip != "":
+    tooltipStr = """ title="$1"""" % [ esc(d.target, tooltip) ]
   if external:
     dispA(d.target, result,
-      "<a class=\"reference external\" href=\"$2\">$1</a>",
-      "\\href{$2}{$1}", [textStr, linkStr])
+      "<a class=\"reference external$3\"$4 href=\"$2\">$1</a>",
+      "\\href{$2}{$1}", [textStr, linkStr, nimDocStr, tooltipStr])
   else:
     dispA(d.target, result,
-      "<a class=\"reference internal\" href=\"#$2\">$1</a>",
-      "\\hyperlink{$2}{$1} (p.~\\pageref{$2})", [textStr, linkStr])
+      "<a class=\"reference internal$3\"$4 href=\"#$2\">$1</a>",
+      "\\hyperlink{$2}{$1} (p.~\\pageref{$2})",
+      [textStr, linkStr, nimDocStr, tooltipStr])
 
 proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   if n == nil: return
@@ -1329,6 +1337,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
     renderHyperlink(d, text=n.sons[0], link=n.sons[0], result, external=true)
   of rnInternalRef:
     renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false)
+  of rnNimdocRef:
+    renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=false,
+                    nimdoc=true, tooltip=n.tooltip)
   of rnHyperlink:
     renderHyperlink(d, text=n.sons[0], link=n.sons[1], result, external=true)
   of rnFootnoteRef:
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 873949ca6..2234a8625 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -273,6 +273,11 @@ func nimIdentNormalize*(s: string): string =
   ##
   ## That means to convert to lower case and remove any '_' on all characters
   ## except first one.
+  ##
+  ## .. Warning:: Backticks (`) are not handled: they remain *as is* and
+  ##    spaces are preserved. See `nimIdentBackticksNormalize 
+  ##    <dochelpers.html#nimIdentBackticksNormalize,string>`_ for
+  ##    an alternative approach.
   runnableExamples:
     doAssert nimIdentNormalize("Foo_bar") == "Foobar"
   result = newString(s.len)
diff --git a/nimdoc/test_out_index_dot_html/expected/index.html b/nimdoc/test_out_index_dot_html/expected/index.html
index 3499b5326..69dd2eb2e 100644
--- a/nimdoc/test_out_index_dot_html/expected/index.html
+++ b/nimdoc/test_out_index_dot_html/expected/index.html
@@ -121,6 +121,8 @@ window.addEventListener('DOMContentLoaded', main);
   <div class="section" id="12">
 <h1><a class="toc-backref" href="#12">Procs</a></h1>
 <dl class="item">
+
+<div id="foo-procs-all">
 <div id="foo">
 <dt><pre><span class="Keyword">proc</span> <a href="#foo"><span class="Identifier">foo</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -130,6 +132,8 @@ I do foo
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 
   </div>
diff --git a/nimdoc/testproject/expected/nimdoc.out.css b/nimdoc/testproject/expected/nimdoc.out.css
index 3353f1cda..7c819ea30 100644
--- a/nimdoc/testproject/expected/nimdoc.out.css
+++ b/nimdoc/testproject/expected/nimdoc.out.css
@@ -263,6 +263,10 @@ a.reference-toplevel {
   font-weight: bold;

 }

 

+a.nimdoc {

+  word-spacing: 0.3em;

+}

+

 a.toc-backref {

   text-decoration: none;

   color: var(--text); }

diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
index 47901ce0d..c64039941 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
@@ -106,7 +106,10 @@ window.addEventListener('DOMContentLoaded', main);
 </ul><li>
   <a class="reference reference-toplevel" href="#7" id="57">Types</a>
   <ul class="simple simple-toc-section">
-      <li><a class="reference" href="#SomeType"
+      <li><a class="reference" href="#G"
+    title="G[T] = object
+  val: T">G</a></li>
+  <li><a class="reference" href="#SomeType"
     title="SomeType = enum
   enumValueA, enumValueB, enumValueC">SomeType</a></li>
 
@@ -115,9 +118,54 @@ window.addEventListener('DOMContentLoaded', main);
 <li>
   <a class="reference reference-toplevel" href="#12" id="62">Procs</a>
   <ul class="simple simple-toc-section">
-      <ul class="simple nested-toc-section">fn2
+      <ul class="simple nested-toc-section">$
+      <li><a class="reference" href="#%24%2CG%5BT%5D"
+    title="`$`[T](a: G[T]): string">`$`[T](a: G[T]): string</a></li>
+  <li><a class="reference" href="#%24%2Cref.SomeType"
+    title="`$`[T](a: ref SomeType): string">`$`[T](a: ref SomeType): string</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">'big
+      <li><a class="reference" href="#%27big%2Cstring"
+    title="`'big`(a: string): SomeType">`'big`(a: string): SomeType</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">[]
+      <li><a class="reference" href="#%5B%5D%2CG%5BT%5D"
+    title="`[]`[T](x: G[T]): T">`[]`[T](x: G[T]): T</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">[]=
+      <li><a class="reference" href="#%5B%5D%3D%2CG%5BT%5D%2Cint%2CT"
+    title="`[]=`[T](a: var G[T]; index: int; value: T)">`[]=`[T](a: var G[T]; index: int; value: T)</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">binarySearch
+      <li><a class="reference" href="#binarySearch%2CopenArray%5BT%5D%2CK%2Cproc%28T%2CK%29"
+    title="binarySearch[T, K](a: openArray[T]; key: K;
+                   cmp: proc (x: T; y: K): int {.closure.}): int">binarySearch[T, K](a: openArray[T]; key: K;
+                   cmp: proc (x: T; y: K): int {.closure.}): int</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">f
+      <li><a class="reference" href="#f%2CG%5Bint%5D"
+    title="f(x: G[int])">f(x: G[int])</a></li>
+  <li><a class="reference" href="#f%2CG%5Bstring%5D"
+    title="f(x: G[string])">f(x: G[string])</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">fn
+      <li><a class="reference" href="#fn"
+    title="fn[T; U, V: SomeFloat]()">fn[T; U, V: SomeFloat]()</a></li>
+
+  </ul>
+  <ul class="simple nested-toc-section">fn2
       <li><a class="reference" href="#fn2"
     title="fn2()">fn2()</a></li>
+  <li><a class="reference" href="#fn2%2Cint"
+    title="fn2(x: int)">fn2(x: int)</a></li>
+  <li><a class="reference" href="#fn2%2Cint%2Cfloat"
+    title="fn2(x: int; y: float)">fn2(x: int; y: float)</a></li>
 
   </ul>
   <ul class="simple nested-toc-section">fn3
@@ -160,6 +208,11 @@ window.addEventListener('DOMContentLoaded', main);
     title="fn10(a: int): int">fn10(a: int): int</a></li>
 
   </ul>
+  <ul class="simple nested-toc-section">funWithGenerics
+      <li><a class="reference" href="#funWithGenerics%2CT%2CU"
+    title="funWithGenerics[T, U: SomeFloat](a: T; b: U)">funWithGenerics[T, U: SomeFloat](a: T; b: U)</a></li>
+
+  </ul>
   <ul class="simple nested-toc-section">someType
       <li><a class="reference" href="#someType_2"
     title="someType(): SomeType">someType(): SomeType</a></li>
@@ -169,6 +222,17 @@ window.addEventListener('DOMContentLoaded', main);
   </ul>
 </li>
 <li>
+  <a class="reference reference-toplevel" href="#15" id="65">Iterators</a>
+  <ul class="simple simple-toc-section">
+      <ul class="simple nested-toc-section">fooBar
+      <li><a class="reference" href="#fooBar.i%2Cseq%5BSomeType%5D"
+    title="fooBar(a: seq[SomeType]): int">fooBar(a: seq[SomeType]): int</a></li>
+
+  </ul>
+
+  </ul>
+</li>
+<li>
   <a class="reference reference-toplevel" href="#18" id="68">Templates</a>
   <ul class="simple simple-toc-section">
       <ul class="simple nested-toc-section">aEnum
@@ -197,7 +261,13 @@ window.addEventListener('DOMContentLoaded', main);
   <div class="nine columns" id="content">
   <div id="tocRoot"></div>
   
-  <p class="module-desc">
+  <p class="module-desc"><p>This is a description of the utils module.</p>
+<p>Links work:</p>
+<ul class="simple"><li>other module: <a class="reference external" href="iterator.html">iterators</a> (not in this dir, just an example)</li>
+<li>internal: <a class="reference internal nimdoc" title="proc fn2(x: int)" href="#fn2,int">fn2(x)</a></li>
+<li>internal included from another module: <a class="reference internal nimdoc" title="proc funWithGenerics[T, U: SomeFloat](a: T; b: U)" href="#funWithGenerics,T,U">funWithGenerics*[T, U: SomeFloat](a: T, b: U)</a>.</li>
+</ul>
+
 <h1><a class="toc-backref" id="this-is-now-a-header" href="#this-is-now-a-header">This is now a header</a></h1>
 <h2><a class="toc-backref" id="this-is-now-a-header-next-header" href="#this-is-now-a-header-next-header">Next header</a></h2>
 <h3><a class="toc-backref" id="next-header-and-so-on" href="#next-header-and-so-on">And so on</a></h3>
@@ -209,10 +279,31 @@ window.addEventListener('DOMContentLoaded', main);
 <ol class="simple"><li>Other case value</li>
 <li>Second case.</li>
 </ol>
-</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>
+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>
   <div class="section" id="7">
 <h1><a class="toc-backref" href="#7">Types</a></h1>
 <dl class="item">
+<div id="G">
+<dt><pre><a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span> <span class="Other">=</span> <span class="Keyword">object</span>
+  <span class="Identifier">val</span><span class="Other">:</span> <span class="Identifier">T</span>
+</pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
 <div id="SomeType">
 <dt><pre><a href="utils.html#SomeType"><span class="Identifier">SomeType</span></a> <span class="Other">=</span> <span class="Keyword">enum</span>
   <span class="Identifier">enumValueA</span><span class="Other">,</span> <span class="Identifier">enumValueB</span><span class="Other">,</span> <span class="Identifier">enumValueC</span></pre></dt>
@@ -227,6 +318,109 @@ window.addEventListener('DOMContentLoaded', main);
 <div class="section" id="12">
 <h1><a class="toc-backref" href="#12">Procs</a></h1>
 <dl class="item">
+
+<div id="$-procs-all">
+<div id="$,G[T]">
+<dt><pre><span class="Keyword">proc</span> <a href="#%24%2CG%5BT%5D"><span class="Identifier">`$`</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+<div id="$,ref.SomeType">
+<dt><pre><span class="Keyword">proc</span> <a href="#%24%2Cref.SomeType"><span class="Identifier">`$`</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Keyword">ref</span> <a href="utils.html#SomeType"><span class="Identifier">SomeType</span></a><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">string</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="'big-procs-all">
+<div id="'big,string">
+<dt><pre><span class="Keyword">func</span> <a href="#%27big%2Cstring"><span class="Identifier">`'big`</span></a><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">string</span><span class="Other">)</span><span class="Other">:</span> <a href="utils.html#SomeType"><span class="Identifier">SomeType</span></a> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="[]-procs-all">
+<div id="[],G[T]">
+<dt><pre><span class="Keyword">proc</span> <a href="#%5B%5D%2CG%5BT%5D"><span class="Identifier">`[]`</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="[]=-procs-all">
+<div id="[]=,G[T],int,T">
+<dt><pre><span class="Keyword">proc</span> <a href="#%5B%5D%3D%2CG%5BT%5D%2Cint%2CT"><span class="Identifier">`[]=`</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Keyword">var</span> <a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">;</span> <span class="Identifier">index</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">;</span> <span class="Identifier">value</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="binarySearch-procs-all">
+<div id="binarySearch,openArray[T],K,proc(T,K)">
+<dt><pre><span class="Keyword">proc</span> <a href="#binarySearch%2CopenArray%5BT%5D%2CK%2Cproc%28T%2CK%29"><span class="Identifier">binarySearch</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">,</span> <span class="Identifier">K</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">openArray</span><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">;</span> <span class="Identifier">key</span><span class="Other">:</span> <span class="Identifier">K</span><span class="Other">;</span>
+                        <span class="Identifier">cmp</span><span class="Other">:</span> <span class="Keyword">proc</span> <span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">;</span> <span class="Identifier">y</span><span class="Other">:</span> <span class="Identifier">K</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span class="Identifier">closure</span>.}<span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="f-procs-all">
+<div id="f,G[int]">
+<dt><pre><span class="Keyword">proc</span> <a href="#f%2CG%5Bint%5D"><span class="Identifier">f</span></a><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">int</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+There is also variant <a class="reference internal nimdoc" title="proc f(x: G[string])" href="#f,G[string]">f(G[string])</a>
+
+</dd>
+</div>
+<div id="f,G[string]">
+<dt><pre><span class="Keyword">proc</span> <a href="#f%2CG%5Bstring%5D"><span class="Identifier">f</span></a><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <a href="utils.html#G"><span class="Identifier">G</span></a><span class="Other">[</span><span class="Identifier">string</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+See also <a class="reference internal nimdoc" title="proc f(x: G[int])" href="#f,G[int]">f(G[int])</a>.
+
+</dd>
+</div>
+
+</div>
+
+<div id="fn-procs-all">
+<div id="fn">
+<dt><pre><span class="Keyword">proc</span> <a href="#fn"><span class="Identifier">fn</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">;</span> <span class="Identifier">U</span><span class="Other">,</span> <span class="Identifier">V</span><span class="Other">:</span> <span class="Identifier">SomeFloat</span><span class="Other">]</span><span class="Other">(</span><span class="Other">)</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="fn2-procs-all">
 <div id="fn2">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn2"><span class="Identifier">fn2</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -235,6 +429,26 @@ comment
 
 </dd>
 </div>
+<div id="fn2,int">
+<dt><pre><span class="Keyword">proc</span> <a href="#fn2%2Cint"><span class="Identifier">fn2</span></a><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+fn2 comment
+
+</dd>
+</div>
+<div id="fn2,int,float">
+<dt><pre><span class="Keyword">proc</span> <a href="#fn2%2Cint%2Cfloat"><span class="Identifier">fn2</span></a><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">;</span> <span class="Identifier">y</span><span class="Other">:</span> <span class="Identifier">float</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="fn3-procs-all">
 <div id="fn3">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn3"><span class="Identifier">fn3</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">auto</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -243,6 +457,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn4-procs-all">
 <div id="fn4">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn4"><span class="Identifier">fn4</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">auto</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -251,6 +469,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn5-procs-all">
 <div id="fn5">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn5"><span class="Identifier">fn5</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -259,6 +481,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn6-procs-all">
 <div id="fn6">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn6"><span class="Identifier">fn6</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -267,6 +493,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn7-procs-all">
 <div id="fn7">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn7"><span class="Identifier">fn7</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -275,6 +505,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn8-procs-all">
 <div id="fn8">
 <dt><pre><span class="Keyword">proc</span> <a href="#fn8"><span class="Identifier">fn8</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">auto</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -283,6 +517,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn9-procs-all">
 <div id="fn9,int">
 <dt><pre><span class="Keyword">func</span> <a href="#fn9%2Cint"><span class="Identifier">fn9</span></a><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -291,6 +529,10 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="fn10-procs-all">
 <div id="fn10,int">
 <dt><pre><span class="Keyword">func</span> <a href="#fn10%2Cint"><span class="Identifier">fn10</span></a><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -299,6 +541,22 @@ comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="funWithGenerics-procs-all">
+<div id="funWithGenerics,T,U">
+<dt><pre><span class="Keyword">proc</span> <a href="#funWithGenerics%2CT%2CU"><span class="Identifier">funWithGenerics</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">,</span> <span class="Identifier">U</span><span class="Other">:</span> <span class="Identifier">SomeFloat</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">;</span> <span class="Identifier">b</span><span class="Other">:</span> <span class="Identifier">U</span><span class="Other">)</span></pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
+<div id="someType-procs-all">
 <div id="someType_2">
 <dt><pre><span class="Keyword">proc</span> <a href="#someType_2"><span class="Identifier">someType</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <a href="utils.html#SomeType"><span class="Identifier">SomeType</span></a> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -308,10 +566,31 @@ constructor.
 </dd>
 </div>
 
+</div>
+
+</dl></div>
+<div class="section" id="15">
+<h1><a class="toc-backref" href="#15">Iterators</a></h1>
+<dl class="item">
+
+<div id="fooBar-iterators-all">
+<div id="fooBar.i,seq[SomeType]">
+<dt><pre><span class="Keyword">iterator</span> <a href="#fooBar.i%2Cseq%5BSomeType%5D"><span class="Identifier">fooBar</span></a><span class="Other">(</span><span class="Identifier">a</span><span class="Other">:</span> <span class="Identifier">seq</span><span class="Other">[</span><a href="utils.html#SomeType"><span class="Identifier">SomeType</span></a><span class="Other">]</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
+<dd>
+
+
+
+</dd>
+</div>
+
+</div>
+
 </dl></div>
 <div class="section" id="18">
 <h1><a class="toc-backref" href="#18">Templates</a></h1>
 <dl class="item">
+
+<div id="aEnum-templates-all">
 <div id="aEnum.t">
 <dt><pre><span class="Keyword">template</span> <a href="#aEnum.t"><span class="Identifier">aEnum</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
 <dd>
@@ -320,6 +599,10 @@ constructor.
 
 </dd>
 </div>
+
+</div>
+
+<div id="bEnum-templates-all">
 <div id="bEnum.t">
 <dt><pre><span class="Keyword">template</span> <a href="#bEnum.t"><span class="Identifier">bEnum</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
 <dd>
@@ -328,6 +611,10 @@ constructor.
 
 </dd>
 </div>
+
+</div>
+
+<div id="fromUtilsGen-templates-all">
 <div id="fromUtilsGen.t">
 <dt><pre><span class="Keyword">template</span> <a href="#fromUtilsGen.t"><span class="Identifier">fromUtilsGen</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
 <dd>
@@ -339,6 +626,8 @@ should be shown in utils.html only
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 
   </div>
diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
index a87393f09..441bd8675 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.idx
@@ -1,9 +1,14 @@
+funWithGenerics	subdir/subdir_b/utils.html#funWithGenerics,T,U	utils: funWithGenerics[T, U: SomeFloat](a: T; b: U)	
 enumValueA	subdir/subdir_b/utils.html#enumValueA	SomeType.enumValueA	
 enumValueB	subdir/subdir_b/utils.html#enumValueB	SomeType.enumValueB	
 enumValueC	subdir/subdir_b/utils.html#enumValueC	SomeType.enumValueC	
 SomeType	subdir/subdir_b/utils.html#SomeType	utils: SomeType	
+G	subdir/subdir_b/utils.html#G	utils: G	
 someType	subdir/subdir_b/utils.html#someType_2	utils: someType(): SomeType	
 fn2	subdir/subdir_b/utils.html#fn2	utils: fn2()	
+fn2	subdir/subdir_b/utils.html#fn2,int	utils: fn2(x: int)	
+fn2	subdir/subdir_b/utils.html#fn2,int,float	utils: fn2(x: int; y: float)	
+binarySearch	subdir/subdir_b/utils.html#binarySearch,openArray[T],K,proc(T,K)	utils: binarySearch[T, K](a: openArray[T]; key: K;\n                   cmp: proc (x: T; y: K): int {.closure.}): int	
 fn3	subdir/subdir_b/utils.html#fn3	utils: fn3(): auto	
 fn4	subdir/subdir_b/utils.html#fn4	utils: fn4(): auto	
 fn5	subdir/subdir_b/utils.html#fn5	utils: fn5()	
@@ -15,6 +20,15 @@ fn10	subdir/subdir_b/utils.html#fn10,int	utils: fn10(a: int): int
 aEnum	subdir/subdir_b/utils.html#aEnum.t	utils: aEnum(): untyped	
 bEnum	subdir/subdir_b/utils.html#bEnum.t	utils: bEnum(): untyped	
 fromUtilsGen	subdir/subdir_b/utils.html#fromUtilsGen.t	utils: fromUtilsGen(): untyped	
+f	subdir/subdir_b/utils.html#f,G[int]	utils: f(x: G[int])	
+f	subdir/subdir_b/utils.html#f,G[string]	utils: f(x: G[string])	
+`[]`	subdir/subdir_b/utils.html#[],G[T]	utils: `[]`[T](x: G[T]): T	
+`[]=`	subdir/subdir_b/utils.html#[]=,G[T],int,T	utils: `[]=`[T](a: var G[T]; index: int; value: T)	
+`$`	subdir/subdir_b/utils.html#$,G[T]	utils: `$`[T](a: G[T]): string	
+`$`	subdir/subdir_b/utils.html#$,ref.SomeType	utils: `$`[T](a: ref SomeType): string	
+fooBar	subdir/subdir_b/utils.html#fooBar.i,seq[SomeType]	utils: fooBar(a: seq[SomeType]): int	
+fn	subdir/subdir_b/utils.html#fn	utils: fn[T; U, V: SomeFloat]()	
+`'big`	subdir/subdir_b/utils.html#'big,string	utils: `&apos;big`(a: string): SomeType	
 This is now a header	subdir/subdir_b/utils.html#this-is-now-a-header	 This is now a header	
 Next header	subdir/subdir_b/utils.html#this-is-now-a-header-next-header	  Next header	
 And so on	subdir/subdir_b/utils.html#next-header-and-so-on	   And so on	
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html
index dbacb57a7..e45492dac 100644
--- a/nimdoc/testproject/expected/testproject.html
+++ b/nimdoc/testproject/expected/testproject.html
@@ -559,6 +559,8 @@ This should be visible.
 <div class="section" id="12">
 <h1><a class="toc-backref" href="#12">Procs</a></h1>
 <dl class="item">
+
+<div id="addfBug14485-procs-all">
 <div id="addfBug14485">
 <dt><pre><span class="Keyword">proc</span> <a href="#addfBug14485"><span class="Identifier">addfBug14485</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -579,6 +581,10 @@ Some proc
 
 </dd>
 </div>
+
+</div>
+
+<div id="anything-procs-all">
 <div id="anything">
 <dt><pre><span class="Keyword">proc</span> <a href="#anything"><span class="Identifier">anything</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -587,6 +593,10 @@ There is no block quote after blank lines at the beginning.
 
 </dd>
 </div>
+
+</div>
+
+<div id="asyncFun1-procs-all">
 <div id="asyncFun1">
 <dt><pre><span class="Keyword">proc</span> <a href="#asyncFun1"><span class="Identifier">asyncFun1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">int</span><span class="Other">]</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">,</span> <span class="Identifier">ValueError</span><span class="Other">]</span><span class="Other">,</span>
                                 <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
@@ -596,6 +606,10 @@ ok1
 
 </dd>
 </div>
+
+</div>
+
+<div id="asyncFun2-procs-all">
 <div id="asyncFun2">
 <dt><pre><span class="Keyword">proc</span> <a href="#asyncFun2"><span class="Identifier">asyncFun2</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -604,6 +618,10 @@ ok1
 
 </dd>
 </div>
+
+</div>
+
+<div id="asyncFun3-procs-all">
 <div id="asyncFun3">
 <dt><pre><span class="Keyword">proc</span> <a href="#asyncFun3"><span class="Identifier">asyncFun3</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">owned</span><span class="Other">(</span><span class="Identifier">Future</span><span class="Other">[</span><span class="Identifier">void</span><span class="Other">]</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">Exception</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Identifier">RootEffect</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -614,6 +632,10 @@ ok1
 
 </dd>
 </div>
+
+</div>
+
+<div id="bar-procs-all">
 <div id="bar,T,T">
 <dt><pre><span class="Keyword">proc</span> <a href="#bar%2CT%2CT"><span class="Identifier">bar</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">,</span> <span class="Identifier">b</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span></pre></dt>
 <dd>
@@ -622,6 +644,10 @@ ok1
 
 </dd>
 </div>
+
+</div>
+
+<div id="baz-procs-all">
 <div id="baz">
 <dt><pre><span class="Keyword">proc</span> <a href="#baz"><span class="Identifier">baz</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -641,6 +667,10 @@ This is deprecated without message.
 
 </dd>
 </div>
+
+</div>
+
+<div id="buzz-procs-all">
 <div id="buzz,T,T">
 <dt><pre><span class="Keyword">proc</span> <a href="#buzz%2CT%2CT"><span class="Identifier">buzz</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">a</span><span class="Other">,</span> <span class="Identifier">b</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">deprecated</span><span class="Other">:</span> <span class="StringLit">&quot;since v0.20&quot;</span></span>.}</pre></dt>
 <dd>
@@ -652,6 +682,10 @@ This is deprecated with a message.
 
 </dd>
 </div>
+
+</div>
+
+<div id="c_nonexistent-procs-all">
 <div id="c_nonexistent,cstring">
 <dt><pre><span class="Keyword">proc</span> <a href="#c_nonexistent%2Ccstring"><span class="Identifier">c_nonexistent</span></a><span class="Other">(</span><span class="Identifier">frmt</span><span class="Other">:</span> <span class="Identifier">cstring</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">cint</span> {.<span class="Identifier">importc</span><span class="Other">:</span> <span class="StringLit">&quot;nonexistent&quot;</span><span class="Other">,</span>
     <span class="Identifier">header</span><span class="Other">:</span> <span class="StringLit">&quot;&lt;stdio.h&gt;&quot;</span><span class="Other">,</span> <span class="Identifier">varargs</span><span class="Other">,</span> <span class="Identifier">discardable</span><span class="Other">,</span> <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
@@ -661,6 +695,10 @@ This is deprecated with a message.
 
 </dd>
 </div>
+
+</div>
+
+<div id="c_printf-procs-all">
 <div id="c_printf,cstring">
 <dt><pre><span class="Keyword">proc</span> <a href="#c_printf%2Ccstring"><span class="Identifier">c_printf</span></a><span class="Other">(</span><span class="Identifier">frmt</span><span class="Other">:</span> <span class="Identifier">cstring</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">cint</span> {.<span class="Identifier">importc</span><span class="Other">:</span> <span class="StringLit">&quot;printf&quot;</span><span class="Other">,</span> <span class="Identifier">header</span><span class="Other">:</span> <span class="StringLit">&quot;&lt;stdio.h&gt;&quot;</span><span class="Other">,</span>
                                      <span class="Identifier">varargs</span><span class="Other">,</span> <span class="Identifier">discardable</span><span class="Other">,</span> <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
@@ -670,6 +708,10 @@ the c printf. etc.
 
 </dd>
 </div>
+
+</div>
+
+<div id="fromUtils3-procs-all">
 <div id="fromUtils3">
 <dt><pre><span class="Keyword">proc</span> <a href="#fromUtils3"><span class="Identifier">fromUtils3</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -681,6 +723,10 @@ came form utils but should be shown where <tt class="docutils literal"><span cla
 
 </dd>
 </div>
+
+</div>
+
+<div id="isValid-procs-all">
 <div id="isValid,T">
 <dt><pre><span class="Keyword">proc</span> <a href="#isValid%2CT"><span class="Identifier">isValid</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
 <dd>
@@ -689,34 +735,46 @@ came form utils but should be shown where <tt class="docutils literal"><span cla
 
 </dd>
 </div>
-<div id="low2,T">
-<dt><pre><span class="Keyword">proc</span> <a href="#low2%2CT"><span class="Identifier">low2</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">:</span> <span class="Identifier">Ordinal</span> <span class="Operator">|</span> <span class="Keyword">enum</span> <span class="Operator">|</span> <span class="Identifier">range</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span> {.<span class="Identifier">magic</span><span class="Other">:</span> <span class="StringLit">&quot;Low&quot;</span><span class="Other">,</span> <span class="Identifier">noSideEffect</span><span class="Other">,</span>
+
+</div>
+
+<div id="low-procs-all">
+<div id="low,T">
+<dt><pre><span class="Keyword">proc</span> <a href="#low%2CT"><span class="Identifier">low</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">:</span> <span class="Identifier">Ordinal</span> <span class="Operator">|</span> <span class="Keyword">enum</span> <span class="Operator">|</span> <span class="Identifier">range</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span> {.<span class="Identifier">magic</span><span class="Other">:</span> <span class="StringLit">&quot;Low&quot;</span><span class="Other">,</span> <span class="Identifier">noSideEffect</span><span class="Other">,</span>
     <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
 
 <p>Returns the lowest possible value of an ordinal value <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt>. As a special semantic rule, <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> may also be a type identifier.</p>
 <p>See also:</p>
-<ul class="simple"><li><a class="reference external" href="#low,T">low(T)</a></li>
+<ul class="simple"><li><a class="reference external" href="#low2,T">low2(T)</a></li>
 </ul>
-<pre class="listing"><span class="Identifier">low2</span><span class="Punctuation">(</span><span class="DecNumber">2</span><span class="Punctuation">)</span> <span class="Comment"># =&gt; -9223372036854775808</span></pre>
-<p><strong class="examples_text">Example:</strong></p>
-<pre class="listing"><span class="Keyword">discard</span> <span class="StringLit">&quot;in low2&quot;</span></pre>
+<pre class="listing"><span class="Identifier">low</span><span class="Punctuation">(</span><span class="DecNumber">2</span><span class="Punctuation">)</span> <span class="Comment"># =&gt; -9223372036854775808</span></pre>
 
 </dd>
 </div>
-<div id="low,T">
-<dt><pre><span class="Keyword">proc</span> <a href="#low%2CT"><span class="Identifier">low</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">:</span> <span class="Identifier">Ordinal</span> <span class="Operator">|</span> <span class="Keyword">enum</span> <span class="Operator">|</span> <span class="Identifier">range</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span> {.<span class="Identifier">magic</span><span class="Other">:</span> <span class="StringLit">&quot;Low&quot;</span><span class="Other">,</span> <span class="Identifier">noSideEffect</span><span class="Other">,</span>
+
+</div>
+
+<div id="low2-procs-all">
+<div id="low2,T">
+<dt><pre><span class="Keyword">proc</span> <a href="#low2%2CT"><span class="Identifier">low2</span></a><span class="Other">[</span><span class="Identifier">T</span><span class="Other">:</span> <span class="Identifier">Ordinal</span> <span class="Operator">|</span> <span class="Keyword">enum</span> <span class="Operator">|</span> <span class="Identifier">range</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">T</span> {.<span class="Identifier">magic</span><span class="Other">:</span> <span class="StringLit">&quot;Low&quot;</span><span class="Other">,</span> <span class="Identifier">noSideEffect</span><span class="Other">,</span>
     <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
 
 <p>Returns the lowest possible value of an ordinal value <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt>. As a special semantic rule, <tt class="docutils literal"><span class="pre"><span class="Identifier">x</span></span></tt> may also be a type identifier.</p>
 <p>See also:</p>
-<ul class="simple"><li><a class="reference external" href="#low2,T">low2(T)</a></li>
+<ul class="simple"><li><a class="reference external" href="#low,T">low(T)</a></li>
 </ul>
-<pre class="listing"><span class="Identifier">low</span><span class="Punctuation">(</span><span class="DecNumber">2</span><span class="Punctuation">)</span> <span class="Comment"># =&gt; -9223372036854775808</span></pre>
+<pre class="listing"><span class="Identifier">low2</span><span class="Punctuation">(</span><span class="DecNumber">2</span><span class="Punctuation">)</span> <span class="Comment"># =&gt; -9223372036854775808</span></pre>
+<p><strong class="examples_text">Example:</strong></p>
+<pre class="listing"><span class="Keyword">discard</span> <span class="StringLit">&quot;in low2&quot;</span></pre>
 
 </dd>
 </div>
+
+</div>
+
+<div id="p1-procs-all">
 <div id="p1">
 <dt><pre><span class="Keyword">proc</span> <a href="#p1"><span class="Identifier">p1</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -741,6 +799,10 @@ this is a nested doc comment
 
 </dd>
 </div>
+
+</div>
+
+<div id="someFunc-procs-all">
 <div id="someFunc">
 <dt><pre><span class="Keyword">func</span> <a href="#someFunc"><span class="Identifier">someFunc</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -749,6 +811,10 @@ My someFunc. Stuff in <tt class="docutils literal"><span class="pre"><span class
 
 </dd>
 </div>
+
+</div>
+
+<div id="tripleStrLitTest-procs-all">
 <div id="tripleStrLitTest">
 <dt><pre><span class="Keyword">proc</span> <a href="#tripleStrLitTest"><span class="Identifier">tripleStrLitTest</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -793,6 +859,10 @@ at indent 0
 
 </dd>
 </div>
+
+</div>
+
+<div id="z1-procs-all">
 <div id="z1">
 <dt><pre><span class="Keyword">proc</span> <a href="#z1"><span class="Identifier">z1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <a href="testproject.html#Foo"><span class="Identifier">Foo</span></a> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -801,6 +871,10 @@ cz1
 
 </dd>
 </div>
+
+</div>
+
+<div id="z2-procs-all">
 <div id="z2">
 <dt><pre><span class="Keyword">proc</span> <a href="#z2"><span class="Identifier">z2</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -811,6 +885,10 @@ cz2
 
 </dd>
 </div>
+
+</div>
+
+<div id="z3-procs-all">
 <div id="z3">
 <dt><pre><span class="Keyword">proc</span> <a href="#z3"><span class="Identifier">z3</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -819,6 +897,10 @@ cz3
 
 </dd>
 </div>
+
+</div>
+
+<div id="z4-procs-all">
 <div id="z4">
 <dt><pre><span class="Keyword">proc</span> <a href="#z4"><span class="Identifier">z4</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -827,6 +909,10 @@ cz4
 
 </dd>
 </div>
+
+</div>
+
+<div id="z5-procs-all">
 <div id="z5">
 <dt><pre><span class="Keyword">proc</span> <a href="#z5"><span class="Identifier">z5</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -835,6 +921,10 @@ cz5
 
 </dd>
 </div>
+
+</div>
+
+<div id="z6-procs-all">
 <div id="z6">
 <dt><pre><span class="Keyword">proc</span> <a href="#z6"><span class="Identifier">z6</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -843,6 +933,10 @@ cz6
 
 </dd>
 </div>
+
+</div>
+
+<div id="z7-procs-all">
 <div id="z7">
 <dt><pre><span class="Keyword">proc</span> <a href="#z7"><span class="Identifier">z7</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -851,6 +945,10 @@ cz7
 
 </dd>
 </div>
+
+</div>
+
+<div id="z8-procs-all">
 <div id="z8">
 <dt><pre><span class="Keyword">proc</span> <a href="#z8"><span class="Identifier">z8</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -859,6 +957,10 @@ cz8
 
 </dd>
 </div>
+
+</div>
+
+<div id="z9-procs-all">
 <div id="z9">
 <dt><pre><span class="Keyword">proc</span> <a href="#z9"><span class="Identifier">z9</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -869,6 +971,10 @@ cz8
 
 </dd>
 </div>
+
+</div>
+
+<div id="z10-procs-all">
 <div id="z10">
 <dt><pre><span class="Keyword">proc</span> <a href="#z10"><span class="Identifier">z10</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -879,6 +985,10 @@ cz8
 
 </dd>
 </div>
+
+</div>
+
+<div id="z11-procs-all">
 <div id="z11">
 <dt><pre><span class="Keyword">proc</span> <a href="#z11"><span class="Identifier">z11</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -889,6 +999,10 @@ cz8
 
 </dd>
 </div>
+
+</div>
+
+<div id="z12-procs-all">
 <div id="z12">
 <dt><pre><span class="Keyword">proc</span> <a href="#z12"><span class="Identifier">z12</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -899,6 +1013,10 @@ cz8
 
 </dd>
 </div>
+
+</div>
+
+<div id="z13-procs-all">
 <div id="z13">
 <dt><pre><span class="Keyword">proc</span> <a href="#z13"><span class="Identifier">z13</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -909,6 +1027,10 @@ cz13
 
 </dd>
 </div>
+
+</div>
+
+<div id="z17-procs-all">
 <div id="z17">
 <dt><pre><span class="Keyword">proc</span> <a href="#z17"><span class="Identifier">z17</span></a><span class="Other">(</span><span class="Other">)</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -920,10 +1042,14 @@ cz17 rest
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 <div class="section" id="14">
 <h1><a class="toc-backref" href="#14">Methods</a></h1>
 <dl class="item">
+
+<div id="method1-methods-all">
 <div id="method1.e,Moo">
 <dt><pre><span class="Keyword">method</span> <a href="#method1.e%2CMoo"><span class="Identifier">method1</span></a><span class="Other">(</span><span class="Identifier">self</span><span class="Other">:</span> <span class="Identifier">Moo</span><span class="Other">)</span> {.<span class="Identifier">base</span><span class="Other">,</span> <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -932,6 +1058,10 @@ foo1
 
 </dd>
 </div>
+
+</div>
+
+<div id="method2-methods-all">
 <div id="method2.e,Moo">
 <dt><pre><span class="Keyword">method</span> <a href="#method2.e%2CMoo"><span class="Identifier">method2</span></a><span class="Other">(</span><span class="Identifier">self</span><span class="Other">:</span> <span class="Identifier">Moo</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span class="Identifier">base</span><span class="Other">,</span> <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -940,6 +1070,10 @@ foo2
 
 </dd>
 </div>
+
+</div>
+
+<div id="method3-methods-all">
 <div id="method3.e,Moo">
 <dt><pre><span class="Keyword">method</span> <a href="#method3.e%2CMoo"><span class="Identifier">method3</span></a><span class="Other">(</span><span class="Identifier">self</span><span class="Other">:</span> <span class="Identifier">Moo</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span class="Identifier">base</span><span class="Other">,</span> <span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -949,10 +1083,14 @@ foo3
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 <div class="section" id="15">
 <h1><a class="toc-backref" href="#15">Iterators</a></h1>
 <dl class="item">
+
+<div id="fromUtils1-iterators-all">
 <div id="fromUtils1.i">
 <dt><pre><span class="Keyword">iterator</span> <a href="#fromUtils1.i"><span class="Identifier">fromUtils1</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -965,6 +1103,10 @@ foo3
 
 </dd>
 </div>
+
+</div>
+
+<div id="iter1-iterators-all">
 <div id="iter1.i,int">
 <dt><pre><span class="Keyword">iterator</span> <a href="#iter1.i%2Cint"><span class="Identifier">iter1</span></a><span class="Other">(</span><span class="Identifier">n</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -973,6 +1115,10 @@ foo1
 
 </dd>
 </div>
+
+</div>
+
+<div id="iter2-iterators-all">
 <div id="iter2.i,int">
 <dt><pre><span class="Keyword">iterator</span> <a href="#iter2.i%2Cint"><span class="Identifier">iter2</span></a><span class="Other">(</span><span class="Identifier">n</span><span class="Other">:</span> <span class="Identifier">int</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span> {.<span><span class="Other pragmadots">...</span></span><span class="pragmawrap"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span>.}</pre></dt>
 <dd>
@@ -984,10 +1130,14 @@ foo2
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 <div class="section" id="17">
 <h1><a class="toc-backref" href="#17">Macros</a></h1>
 <dl class="item">
+
+<div id="bar-macros-all">
 <div id="bar.m">
 <dt><pre><span class="Keyword">macro</span> <a href="#bar.m"><span class="Identifier">bar</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
 <dd>
@@ -996,6 +1146,10 @@ foo2
 
 </dd>
 </div>
+
+</div>
+
+<div id="z16-macros-all">
 <div id="z16.m">
 <dt><pre><span class="Keyword">macro</span> <a href="#z16.m"><span class="Identifier">z16</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1008,6 +1162,10 @@ foo2
 
 </dd>
 </div>
+
+</div>
+
+<div id="z18-macros-all">
 <div id="z18.m">
 <dt><pre><span class="Keyword">macro</span> <a href="#z18.m"><span class="Identifier">z18</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span></pre></dt>
 <dd>
@@ -1017,10 +1175,14 @@ cz18
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 <div class="section" id="18">
 <h1><a class="toc-backref" href="#18">Templates</a></h1>
 <dl class="item">
+
+<div id="foo-templates-all">
 <div id="foo.t,SomeType,SomeType">
 <dt><pre><span class="Keyword">template</span> <a href="#foo.t%2CSomeType%2CSomeType"><span class="Identifier">foo</span></a><span class="Other">(</span><span class="Identifier">a</span><span class="Other">,</span> <span class="Identifier">b</span><span class="Other">:</span> <a href="subdir/subdir_b/utils.html#SomeType"><span class="Identifier">SomeType</span></a><span class="Other">)</span></pre></dt>
 <dd>
@@ -1029,6 +1191,10 @@ This does nothing
 
 </dd>
 </div>
+
+</div>
+
+<div id="fromUtils2-templates-all">
 <div id="fromUtils2.t">
 <dt><pre><span class="Keyword">template</span> <a href="#fromUtils2.t"><span class="Identifier">fromUtils2</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1040,6 +1206,10 @@ ok3
 
 </dd>
 </div>
+
+</div>
+
+<div id="myfn-templates-all">
 <div id="myfn.t">
 <dt><pre><span class="Keyword">template</span> <a href="#myfn.t"><span class="Identifier">myfn</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1063,6 +1233,10 @@ bar
 
 </dd>
 </div>
+
+</div>
+
+<div id="testNimDocTrailingExample-templates-all">
 <div id="testNimDocTrailingExample.t">
 <dt><pre><span class="Keyword">template</span> <a href="#testNimDocTrailingExample.t"><span class="Identifier">testNimDocTrailingExample</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1073,6 +1247,10 @@ bar
 
 </dd>
 </div>
+
+</div>
+
+<div id="z6t-templates-all">
 <div id="z6t.t">
 <dt><pre><span class="Keyword">template</span> <a href="#z6t.t"><span class="Identifier">z6t</span></a><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">int</span></pre></dt>
 <dd>
@@ -1081,6 +1259,10 @@ cz6t
 
 </dd>
 </div>
+
+</div>
+
+<div id="z14-templates-all">
 <div id="z14.t">
 <dt><pre><span class="Keyword">template</span> <a href="#z14.t"><span class="Identifier">z14</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1091,6 +1273,10 @@ cz14
 
 </dd>
 </div>
+
+</div>
+
+<div id="z15-templates-all">
 <div id="z15.t">
 <dt><pre><span class="Keyword">template</span> <a href="#z15.t"><span class="Identifier">z15</span></a><span class="Other">(</span><span class="Other">)</span></pre></dt>
 <dd>
@@ -1110,6 +1296,8 @@ cz15
 </dd>
 </div>
 
+</div>
+
 </dl></div>
 
   </div>
diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html
index f72f6c37e..da76334d4 100644
--- a/nimdoc/testproject/expected/theindex.html
+++ b/nimdoc/testproject/expected/theindex.html
@@ -71,7 +71,25 @@ window.addEventListener('DOMContentLoaded', main);
   <div class="container">
     <h1 class="title">Index</h1>
     Modules: <a href="subdir/subdir_b/utils.html">subdir/subdir_b/utils</a>, <a href="testproject.html">testproject</a>.<br/><p /><h2>API symbols</h2>
-<dl><dt><a name="A" href="#A"><span>A:</span></a></dt><dd><ul class="simple">
+<dl><dt><a name="%60%24%60" href="#%60%24%60"><span>`$`:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: `$`[T](a: G[T]): string" href="subdir/subdir_b/utils.html#%24%2CG%5BT%5D">utils: `$`[T](a: G[T]): string</a></li>
+          <li><a class="reference external"
+          data-doc-search-tag="utils: `$`[T](a: ref SomeType): string" href="subdir/subdir_b/utils.html#%24%2Cref.SomeType">utils: `$`[T](a: ref SomeType): string</a></li>
+          </ul></dd>
+<dt><a name="%60%27big%60" href="#%60%27big%60"><span>`'big`:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: `&apos;big`(a: string): SomeType" href="subdir/subdir_b/utils.html#%27big%2Cstring">utils: `&apos;big`(a: string): SomeType</a></li>
+          </ul></dd>
+<dt><a name="%60%5B%5D%3D%60" href="#%60%5B%5D%3D%60"><span>`[]=`:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: `[]=`[T](a: var G[T]; index: int; value: T)" href="subdir/subdir_b/utils.html#%5B%5D%3D%2CG%5BT%5D%2Cint%2CT">utils: `[]=`[T](a: var G[T]; index: int; value: T)</a></li>
+          </ul></dd>
+<dt><a name="%60%5B%5D%60" href="#%60%5B%5D%60"><span>`[]`:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: `[]`[T](x: G[T]): T" href="subdir/subdir_b/utils.html#%5B%5D%2CG%5BT%5D">utils: `[]`[T](x: G[T]): T</a></li>
+          </ul></dd>
+<dt><a name="A" href="#A"><span>A:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: A" href="testproject.html#A">testproject: A</a></li>
           </ul></dd>
@@ -123,6 +141,12 @@ window.addEventListener('DOMContentLoaded', main);
 <li><a class="reference external"
           data-doc-search-tag="utils: bEnum(): untyped" href="subdir/subdir_b/utils.html#bEnum.t">utils: bEnum(): untyped</a></li>
           </ul></dd>
+<dt><a name="binarySearch" href="#binarySearch"><span>binarySearch:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: binarySearch[T, K](a: openArray[T]; key: K;
+                   cmp: proc (x: T; y: K): int {.closure.}): int" href="subdir/subdir_b/utils.html#binarySearch%2CopenArray%5BT%5D%2CK%2Cproc%28T%2CK%29">utils: binarySearch[T, K](a: openArray[T]; key: K;
+                   cmp: proc (x: T; y: K): int {.closure.}): int</a></li>
+          </ul></dd>
 <dt><a name="buzz" href="#buzz"><span>buzz:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: buzz[T](a, b: T): T" href="testproject.html#buzz%2CT%2CT">testproject: buzz[T](a, b: T): T</a></li>
@@ -171,6 +195,16 @@ window.addEventListener('DOMContentLoaded', main);
 <li><a class="reference external"
           data-doc-search-tag="SomeType.enumValueC" href="subdir/subdir_b/utils.html#enumValueC">SomeType.enumValueC</a></li>
           </ul></dd>
+<dt><a name="f" href="#f"><span>f:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: f(x: G[int])" href="subdir/subdir_b/utils.html#f%2CG%5Bint%5D">utils: f(x: G[int])</a></li>
+          <li><a class="reference external"
+          data-doc-search-tag="utils: f(x: G[string])" href="subdir/subdir_b/utils.html#f%2CG%5Bstring%5D">utils: f(x: G[string])</a></li>
+          </ul></dd>
+<dt><a name="fn" href="#fn"><span>fn:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: fn[T; U, V: SomeFloat]()" href="subdir/subdir_b/utils.html#fn">utils: fn[T; U, V: SomeFloat]()</a></li>
+          </ul></dd>
 <dt><a name="fn10" href="#fn10"><span>fn10:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="utils: fn10(a: int): int" href="subdir/subdir_b/utils.html#fn10%2Cint">utils: fn10(a: int): int</a></li>
@@ -178,6 +212,10 @@ window.addEventListener('DOMContentLoaded', main);
 <dt><a name="fn2" href="#fn2"><span>fn2:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="utils: fn2()" href="subdir/subdir_b/utils.html#fn2">utils: fn2()</a></li>
+          <li><a class="reference external"
+          data-doc-search-tag="utils: fn2(x: int)" href="subdir/subdir_b/utils.html#fn2%2Cint">utils: fn2(x: int)</a></li>
+          <li><a class="reference external"
+          data-doc-search-tag="utils: fn2(x: int; y: float)" href="subdir/subdir_b/utils.html#fn2%2Cint%2Cfloat">utils: fn2(x: int; y: float)</a></li>
           </ul></dd>
 <dt><a name="fn3" href="#fn3"><span>fn3:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
@@ -215,6 +253,10 @@ window.addEventListener('DOMContentLoaded', main);
 <li><a class="reference external"
           data-doc-search-tag="testproject: foo(a, b: SomeType)" href="testproject.html#foo.t%2CSomeType%2CSomeType">testproject: foo(a, b: SomeType)</a></li>
           </ul></dd>
+<dt><a name="fooBar" href="#fooBar"><span>fooBar:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: fooBar(a: seq[SomeType]): int" href="subdir/subdir_b/utils.html#fooBar.i%2Cseq%5BSomeType%5D">utils: fooBar(a: seq[SomeType]): int</a></li>
+          </ul></dd>
 <dt><a name="FooBuzz" href="#FooBuzz"><span>FooBuzz:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: FooBuzz" href="testproject.html#FooBuzz">testproject: FooBuzz</a></li>
@@ -235,6 +277,14 @@ window.addEventListener('DOMContentLoaded', main);
 <li><a class="reference external"
           data-doc-search-tag="utils: fromUtilsGen(): untyped" href="subdir/subdir_b/utils.html#fromUtilsGen.t">utils: fromUtilsGen(): untyped</a></li>
           </ul></dd>
+<dt><a name="funWithGenerics" href="#funWithGenerics"><span>funWithGenerics:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: funWithGenerics[T, U: SomeFloat](a: T; b: U)" href="subdir/subdir_b/utils.html#funWithGenerics%2CT%2CU">utils: funWithGenerics[T, U: SomeFloat](a: T; b: U)</a></li>
+          </ul></dd>
+<dt><a name="G" href="#G"><span>G:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: G" href="subdir/subdir_b/utils.html#G">utils: G</a></li>
+          </ul></dd>
 <dt><a name="isValid" href="#isValid"><span>isValid:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: isValid[T](x: T): bool" href="testproject.html#isValid%2CT">testproject: isValid[T](x: T): bool</a></li>
diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim
index 37c91dd3c..5d881e620 100644
--- a/nimdoc/testproject/subdir/subdir_b/utils.nim
+++ b/nimdoc/testproject/subdir/subdir_b/utils.nim
@@ -1,5 +1,7 @@
 ##[
 
+.. include:: ./utils_overview.rst
+
 # This is now a header
 
 ## Next header
@@ -19,13 +21,32 @@ More text.
 1. Other case value
 2. Second case.
 
+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]`_.
+
 ]##
 
+include ./utils_helpers
+
 type
   SomeType* = enum
     enumValueA,
     enumValueB,
     enumValueC
+  G*[T] = object
+    val: T
 
 proc someType*(): SomeType =
   ## constructor.
@@ -33,6 +54,14 @@ proc someType*(): SomeType =
 
 
 proc fn2*() = discard ## comment
+proc fn2*(x: int) =
+  ## fn2 comment
+  discard
+proc fn2*(x: int, y: float) =
+  discard
+proc binarySearch*[T, K](a: openArray[T]; key: K;
+                         cmp: proc (x: T; y: K): int {.closure.}): int =
+  discard
 proc fn3*(): auto = 1 ## comment
 proc fn4*(): auto = 2 * 3 + 4 ## comment
 proc fn5*() ## comment
@@ -89,3 +118,39 @@ template fromUtilsGen*(): untyped =
     ## came form utils but should be shown where `fromUtilsGen` is called
     runnableExamples: discard """should be shown as examples for fromUtils3
        in module calling fromUtilsGen"""
+
+proc f*(x: G[int]) =
+  ## There is also variant `f(G[string])`_
+  discard
+proc f*(x: G[string]) =
+  ## See also `f(G[int])`_.
+  discard
+
+## Ref. `[]`_ is the same as `proc \`[]\`(G[T])`_ because there are no
+## overloads. The full form: `proc \`[]\`*[T](x: G[T]): T`_
+
+proc `[]`*[T](x: G[T]): T = x.val
+
+## Ref. `[]=`_ aka `\`[]=\`(G[T], int, T)`_.
+
+proc `[]=`*[T](a: var G[T], index: int, value: T) = discard
+
+## Ref. `$`_ aka `proc $`_ or `proc \`$\``_.
+
+proc `$`*[T](a: G[T]): string = ""
+
+## Ref. `$(a: ref SomeType)`_.
+
+proc `$`*[T](a: ref SomeType): string = ""
+
+## Ref. foo_bar_ aka `iterator foo_bar_`_.
+
+iterator fooBar*(a: seq[SomeType]): int = discard
+
+## Ref. `fn[T; U,V: SomeFloat]()`_.
+
+proc fn*[T; U, V: SomeFloat]() = discard
+
+## Ref. `'big`_ or `func \`'big\``_ or `\`'big\`(string)`_.
+
+func `'big`*(a: string): SomeType = discard
diff --git a/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim
new file mode 100644
index 000000000..2c45ffb83
--- /dev/null
+++ b/nimdoc/testproject/subdir/subdir_b/utils_helpers.nim
@@ -0,0 +1 @@
+proc funWithGenerics*[T, U: SomeFloat](a: T, b: U) = discard
diff --git a/nimdoc/testproject/subdir/subdir_b/utils_overview.rst b/nimdoc/testproject/subdir/subdir_b/utils_overview.rst
new file mode 100644
index 000000000..58ce930bf
--- /dev/null
+++ b/nimdoc/testproject/subdir/subdir_b/utils_overview.rst
@@ -0,0 +1,8 @@
+This is a description of the utils module.
+
+Links work:
+
+* other module: `iterators <iterator.html>`_ (not in this dir, just an example)
+* internal: `fn2(x)`_
+* internal included from another module: `funWithGenerics*[T, U:
+  SomeFloat](a: T, b: U)`_.
diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim
new file mode 100644
index 000000000..5bcdf32d5
--- /dev/null
+++ b/tests/stdlib/tdochelpers.nim
@@ -0,0 +1,155 @@
+discard """
+  output: '''
+
+[Suite] Integration with Nim
+'''
+"""
+
+# tests for dochelpers.nim module
+
+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
+  let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
+                   {roPreferMarkdown, roSupportMarkdown, roNimFile},
+                   msgHandler=testMsgHandler)
+  result = r.node
+
+suite "Integration with Nim":
+  test "simple symbol parsing (shortest form)":
+    let input1 = "g_".rstParseTest
+    check input1.toLangSymbol == LangSymbol(symKind: "", name: "g")
+
+  test "simple symbol parsing (group of words)":
+    let input1 = "`Y`_".rstParseTest
+    check input1.toLangSymbol == LangSymbol(symKind: "", name: "Y")
+
+    # this means not a statement 'type', it's a backticked identifier `type`:
+    let input2 = "`type`_".rstParseTest
+    check input2.toLangSymbol == LangSymbol(symKind: "", name: "type")
+
+    let input3 = "`[]`_".rstParseTest
+    check input3.toLangSymbol == LangSymbol(symKind: "", name: "[]")
+
+    let input4 = "`X Y Z`_".rstParseTest
+    check input4.toLangSymbol == LangSymbol(symKind: "", name: "Xyz")
+
+  test "simple proc parsing":
+    let input1 = "proc f".rstParseTest
+    check input1.toLangSymbol == LangSymbol(symKind: "proc", name: "f")
+
+  test "another backticked name":
+    let input1 = """`template \`type\``_""".rstParseTest
+    check input1.toLangSymbol == LangSymbol(symKind: "template", name: "type")
+
+  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
+
+  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
+
+  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 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)
+
+  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 expected = LangSymbol(symKind: "proc",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(input.toLangSymbol == 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
+    let expected = LangSymbol(symKind: "",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(input.toLangSymbol == 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 expected = LangSymbol(symKind: "func",
+                              name: "$",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]")],
+                              parametersProvided: true,
+                              outType: "string")
+    check(input1.toLangSymbol == expected)
+    check(input2.toLangSymbol == 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 expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check(input1.toLangSymbol == expected)
+    check(input2.toLangSymbol == expected)
+
+  test "postfix symbol specifier #1":
+    let input = """`walkDir iterator`_""".
+                  rstParseTest
+    let expected = LangSymbol(symKind: "iterator",
+                              name: "walkdir")
+    check(input.toLangSymbol == 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 expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check(input1.toLangSymbol == expected)
+    check(input2.toLangSymbol == expected)
diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim
index e9f67324c..e4609a671 100644
--- a/tests/stdlib/trst.nim
+++ b/tests/stdlib/trst.nim
@@ -17,9 +17,7 @@ discard """
 
 # tests for rst module
 
-import ../../lib/packages/docutils/rstgen
-import ../../lib/packages/docutils/rst
-import ../../lib/packages/docutils/rstast
+import ../../lib/packages/docutils/[rstgen, rst, rstast]
 import unittest, strutils
 import std/private/miscdollars
 import os
@@ -61,6 +59,52 @@ proc toAst(input: string,
       result = e.msg
 
 suite "RST parsing":
+  test "References are whitespace-neutral and case-insensitive":
+    # refname is 'lexical-analysis', the same for all the 3 variants:
+    check(dedent"""
+        Lexical Analysis
+        ================
+
+        Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
+        """.toAst ==
+      dedent"""
+        rnInner
+          rnHeadline  level=1
+            rnLeaf  'Lexical'
+            rnLeaf  ' '
+            rnLeaf  'Analysis'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  '.'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'Analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  '.'
+            rnLeaf  ' '
+      """)
+
   test "option list has priority over definition list":
     check(dedent"""
         --defusages
@@ -376,9 +420,9 @@ suite "Warnings":
     let output = input.toAst(warnings=warnings)
     check(warnings[] == @[
         "input(3, 14) Warning: broken link 'citation-som'",
-        "input(5, 7) Warning: broken link 'a-broken-link'",
+        "input(5, 7) Warning: broken link 'a broken Link'",
         "input(7, 15) Warning: unknown substitution 'undefined subst'",
-        "input(9, 6) Warning: broken link 'shortdotlink'"
+        "input(9, 6) Warning: broken link 'short.link'"
         ])
 
   test "With include directive and blank lines at the beginning":
@@ -391,7 +435,7 @@ suite "Warnings":
     let input = ".. include:: other.rst"
     var warnings = new seq[string]
     let output = input.toAst(warnings=warnings)
-    check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenlink'"]
+    check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
     check(output == dedent"""
       rnInner
         rnParagraph
@@ -404,6 +448,59 @@ suite "Warnings":
       """)
     removeFile("other.rst")
 
+  test "warnings for ambiguous links (references + anchors)":
+    # Reference like `x`_ generates a link alias x that may clash with others
+    let input = dedent"""
+      Manual reference: `foo <#foo,string,string>`_
+
+      .. _foo:
+
+      Paragraph.
+
+      Ref foo_
+      """
+    var warnings = new seq[string]
+    let output = input.toAst(warnings=warnings)
+    check(warnings[] == @[
+      dedent """
+      input(7, 5) Warning: ambiguous doc link `foo`
+        clash:
+          (3, 8): (manual directive anchor)
+          (1, 45): (implicitly-generated hyperlink alias)"""
+    ])
+    # reference should be resolved to the manually set anchor:
+    check(output ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Manual'
+            rnLeaf  ' '
+            rnLeaf  'reference'
+            rnLeaf  ':'
+            rnLeaf  ' '
+            rnHyperlink
+              rnInner
+                rnLeaf  'foo'
+              rnInner
+                rnLeaf  '#'
+                rnLeaf  'foo'
+                rnLeaf  ','
+                rnLeaf  'string'
+                rnLeaf  ','
+                rnLeaf  'string'
+          rnParagraph  anchor='foo'
+            rnLeaf  'Paragraph'
+            rnLeaf  '.'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'foo'
+              rnLeaf  'foo'
+            rnLeaf  ' '
+      """)
+
 suite "RST include directive":
   test "Include whole":
     "other.rst".writeFile("**test1**")
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index 867677404..45cf1a68e 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1054,8 +1054,9 @@ Test1
       Paragraph2 ref `internal anchor`_.
       """
     let output9 = input9.toHtml
-    #doAssert "id=\"internal-anchor\"" in output9
-    #doAssert "internal anchor" notin output9
+    # _`internal anchor` got erased:
+    check "href=\"#internal-anchor\"" notin output9
+    check "href=\"#citation-another\"" in output9
     doAssert output9.count("<hr class=\"footnote\">" &
                            "<div class=\"footnote-group\">") == 1
     doAssert output9.count("<div class=\"footnote-label\">") == 3
@@ -1330,12 +1331,12 @@ Test1
     """
     let output1 = input1.toHtml
     # "target101" should be erased and changed to "section-xyz":
-    doAssert "href=\"#target101\"" notin output1
-    doAssert "id=\"target101\""    notin output1
-    doAssert "href=\"#target102\"" notin output1
-    doAssert "id=\"target102\""    notin output1
-    doAssert "id=\"section-xyz\""     in output1
-    doAssert "href=\"#section-xyz\""  in output1
+    check "href=\"#target101\"" notin output1
+    check "id=\"target101\""    notin output1
+    check "href=\"#target102\"" notin output1
+    check "id=\"target102\""    notin output1
+    check "id=\"section-xyz\""     in output1
+    check "href=\"#section-xyz\""  in output1
 
     let input2 = dedent """
       .. _target300:
@@ -1405,7 +1406,7 @@ Test1
     let output1 = input1.toHtml
     doAssert "id=\"secdot1\"" in output1
     doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1
-    doAssert "id=\"linkdot1-2021\"" in output1
+    check "id=\"linkdot1-2021\"" in output1
     let ref1 = "<a class=\"reference internal\" href=\"#secdot1\">sec.1</a>"
     let ref2 = "<a class=\"reference internal\" href=\"#Z2minusothercolonsecplusc-2\">2-other:sec+c_2</a>"
     let ref3 = "<a class=\"reference internal\" href=\"#linkdot1-2021\">link.1_2021</a>"